]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/spin/mesg.c
ip/ipconfig: use ewrite() to enable routing command for sendra
[plan9front.git] / sys / src / cmd / spin / mesg.c
1 /***** spin: mesg.c *****/
2
3 /*
4  * This file is part of the public release of Spin. It is subject to the
5  * terms in the LICENSE file that is included in this source directory.
6  * Tool documentation is available at http://spinroot.com
7  */
8
9 #include <stdlib.h>
10 #include "spin.h"
11 #include "y.tab.h"
12
13 #ifndef MAXQ
14 #define MAXQ    2500            /* default max # queues  */
15 #endif
16
17 extern RunList  *X;
18 extern Symbol   *Fname;
19 extern Lextok   *Mtype;
20 extern int      verbose, TstOnly, s_trail, analyze, columns;
21 extern int      lineno, depth, xspin, m_loss, jumpsteps;
22 extern int      nproc, nstop;
23 extern short    Have_claim;
24
25 QH      *qh;
26 Queue   *qtab = (Queue *) 0;    /* linked list of queues */
27 Queue   *ltab[MAXQ];            /* linear list of queues */
28 int     nqs = 0, firstrow = 1, has_stdin = 0;
29 char    Buf[4096];
30
31 static Lextok   *n_rem = (Lextok *) 0;
32 static Queue    *q_rem = (Queue  *) 0;
33
34 static int      a_rcv(Queue *, Lextok *, int);
35 static int      a_snd(Queue *, Lextok *);
36 static int      sa_snd(Queue *, Lextok *);
37 static int      s_snd(Queue *, Lextok *);
38 extern void     sr_buf(int, int);
39 extern void     sr_mesg(FILE *, int, int);
40 extern void     putarrow(int, int);
41 static void     sr_talk(Lextok *, int, char *, char *, int, Queue *);
42
43 int
44 cnt_mpars(Lextok *n)
45 {       Lextok *m;
46         int i=0;
47
48         for (m = n; m; m = m->rgt)
49                 i += Cnt_flds(m);
50         return i;
51 }
52
53 int
54 qmake(Symbol *s)
55 {       Lextok *m;
56         Queue *q;
57         int i;
58
59         if (!s->ini)
60                 return 0;
61
62         if (nqs >= MAXQ)
63         {       lineno = s->ini->ln;
64                 Fname  = s->ini->fn;
65                 fatal("too many queues (%s)", s->name);
66         }
67         if (analyze && nqs >= 255)
68         {       fatal("too many channel types", (char *)0);
69         }
70
71         if (s->ini->ntyp != CHAN)
72                 return eval(s->ini);
73
74         q = (Queue *) emalloc(sizeof(Queue));
75         q->qid    = (short) ++nqs;
76         q->nslots = s->ini->val;
77         q->nflds  = cnt_mpars(s->ini->rgt);
78         q->setat  = depth;
79
80         i = max(1, q->nslots);  /* 0-slot qs get 1 slot minimum */
81
82         q->contents  = (int *) emalloc(q->nflds*i*sizeof(int));
83         q->fld_width = (int *) emalloc(q->nflds*sizeof(int));
84         q->stepnr = (int *)   emalloc(i*sizeof(int));
85
86         for (m = s->ini->rgt, i = 0; m; m = m->rgt)
87         {       if (m->sym && m->ntyp == STRUCT)
88                         i = Width_set(q->fld_width, i, getuname(m->sym));
89                 else
90                         q->fld_width[i++] = m->ntyp;
91         }
92         q->nxt = qtab;
93         qtab = q;
94         ltab[q->qid-1] = q;
95
96         return q->qid;
97 }
98
99 int
100 qfull(Lextok *n)
101 {       int whichq = eval(n->lft)-1;
102
103         if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
104                 return (ltab[whichq]->qlen >= ltab[whichq]->nslots);
105         return 0;
106 }
107
108 int
109 qlen(Lextok *n)
110 {       int whichq = eval(n->lft)-1;
111
112         if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
113                 return ltab[whichq]->qlen;
114         return 0;
115 }
116
117 int
118 q_is_sync(Lextok *n)
119 {       int whichq = eval(n->lft)-1;
120
121         if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
122                 return (ltab[whichq]->nslots == 0);
123         return 0;
124 }
125
126 int
127 qsend(Lextok *n)
128 {       int whichq = eval(n->lft)-1;
129
130         if (whichq == -1)
131         {       printf("Error: sending to an uninitialized chan\n");
132                 /* whichq = 0; */
133                 return 0;
134         }
135         if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
136         {       ltab[whichq]->setat = depth;
137                 if (ltab[whichq]->nslots > 0)
138                         return a_snd(ltab[whichq], n);
139                 else
140                         return s_snd(ltab[whichq], n);
141         }
142         return 0;
143 }
144
145 #ifndef PC
146  #include <termios.h>
147  static struct termios initial_settings, new_settings;
148
149  void
150  peek_ch_init(void)
151  {
152         tcgetattr(0,&initial_settings);
153  
154         new_settings = initial_settings;
155         new_settings.c_lflag &= ~ICANON;
156         new_settings.c_lflag &= ~ECHO;
157         new_settings.c_lflag &= ~ISIG;
158         new_settings.c_cc[VMIN] = 0;
159         new_settings.c_cc[VTIME] = 0;
160  }
161
162  int
163  peek_ch(void)
164  {      int n;
165
166         has_stdin = 1;
167
168         tcsetattr(0, TCSANOW, &new_settings);
169         n = getchar();
170         tcsetattr(0, TCSANOW, &initial_settings);
171
172         return n;
173  }
174 #endif
175
176 int
177 qrecv(Lextok *n, int full)
178 {       int whichq = eval(n->lft)-1;
179
180         if (whichq == -1)
181         {       if (n->sym && !strcmp(n->sym->name, "STDIN"))
182                 {       Lextok *m;
183 #ifndef PC
184                         static int did_once = 0;
185                         if (!did_once) /* 6.2.4 */
186                         {       peek_ch_init();
187                                 did_once = 1;
188                         }
189 #endif
190                         if (TstOnly) return 1;
191
192                         for (m = n->rgt; m; m = m->rgt)
193                         if (m->lft->ntyp != CONST && m->lft->ntyp != EVAL)
194                         {
195 #ifdef PC
196                                 int c = getchar();
197 #else
198                                 int c = peek_ch();      /* 6.2.4, was getchar(); */
199 #endif
200                                 if (c == 27 || c == 3)  /* escape or control-c */
201                                 {       printf("quit\n");
202                                         exit(0);
203                                 } /* else: non-blocking */
204                                 if (c == EOF) return 0; /* no char available */
205                                 (void) setval(m->lft, c);
206                         } else
207                         {       fatal("invalid use of STDIN", (char *)0);
208                         }
209                         return 1;
210                 }
211                 printf("Error: receiving from an uninitialized chan %s\n",
212                         n->sym?n->sym->name:"");
213                 /* whichq = 0; */
214                 return 0;
215         }
216         if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
217         {       ltab[whichq]->setat = depth;
218                 return a_rcv(ltab[whichq], n, full);
219         }
220         return 0;
221 }
222
223 static int
224 sa_snd(Queue *q, Lextok *n)     /* sorted asynchronous */
225 {       Lextok *m;
226         int i, j, k;
227         int New, Old;
228
229         for (i = 0; i < q->qlen; i++)
230         for (j = 0, m = n->rgt; m && j < q->nflds; m = m->rgt, j++)
231         {       New = cast_val(q->fld_width[j], eval(m->lft), 0);
232                 Old = q->contents[i*q->nflds+j];
233                 if (New == Old)
234                         continue;
235                 if (New >  Old)
236                         break;  /* inner loop */
237                 goto found;     /* New < Old */
238         }
239 found:
240         for (j = q->qlen-1; j >= i; j--)
241         for (k = 0; k < q->nflds; k++)
242         {       q->contents[(j+1)*q->nflds+k] =
243                         q->contents[j*q->nflds+k];      /* shift up */
244                 if (k == 0)
245                         q->stepnr[j+1] = q->stepnr[j];
246         }
247         return i*q->nflds;                              /* new q offset */
248 }
249
250 void
251 typ_ck(int ft, int at, char *s)
252 {
253         if ((verbose&32) && ft != at
254         && (ft == CHAN || at == CHAN)
255         && (at != PREDEF || strcmp(s, "recv") != 0))
256         {       char buf[128], tag1[64], tag2[64];
257                 (void) sputtype(tag1, ft);
258                 (void) sputtype(tag2, at);
259                 sprintf(buf, "type-clash in %s, (%s<-> %s)", s, tag1, tag2);
260                 non_fatal("%s", buf);
261         }
262 }
263
264 static int
265 a_snd(Queue *q, Lextok *n)
266 {       Lextok *m;
267         int i = q->qlen*q->nflds;       /* q offset */
268         int j = 0;                      /* q field# */
269
270         if (q->nslots > 0 && q->qlen >= q->nslots)
271                 return m_loss;  /* q is full */
272
273         if (TstOnly) return 1;
274
275         if (n->val) i = sa_snd(q, n);   /* sorted insert */
276
277         q->stepnr[i/q->nflds] = depth;
278
279         for (m = n->rgt; m && j < q->nflds; m = m->rgt, j++)
280         {       int New = eval(m->lft);
281                 q->contents[i+j] = cast_val(q->fld_width[j], New, 0);
282                 if ((verbose&16) && depth >= jumpsteps)
283                         sr_talk(n, New, "Send ", "->", j, q);
284                 typ_ck(q->fld_width[j], Sym_typ(m->lft), "send");
285         }
286         if ((verbose&16) && depth >= jumpsteps)
287         {       for (i = j; i < q->nflds; i++)
288                         sr_talk(n, 0, "Send ", "->", i, q);
289                 if (j < q->nflds)
290                         printf("%3d: warning: missing params in send\n",
291                                 depth);
292                 if (m)
293                         printf("%3d: warning: too many params in send\n",
294                                 depth);
295         }
296         q->qlen++;
297         return 1;
298 }
299
300 static int
301 a_rcv(Queue *q, Lextok *n, int full)
302 {       Lextok *m;
303         int i=0, oi, j, k;
304         extern int Rvous;
305
306         if (q->qlen == 0)
307                 return 0;       /* q is empty */
308 try_slot:
309         /* test executability */
310         for (m = n->rgt, j=0; m && j < q->nflds; m = m->rgt, j++)
311                 if ((m->lft->ntyp == CONST
312                    && q->contents[i*q->nflds+j] != m->lft->val)
313                 ||  (m->lft->ntyp == EVAL
314                    && q->contents[i*q->nflds+j] != eval(m->lft->lft)))
315                 {       if (n->val == 0         /* fifo recv */
316                         ||  n->val == 2         /* fifo poll */
317                         || ++i >= q->qlen)      /* last slot */
318                                 return 0;       /* no match  */
319                         goto try_slot;
320                 }
321         if (TstOnly) return 1;
322
323         if (verbose&8)
324         {       if (j < q->nflds)
325                         printf("%3d: warning: missing params in next recv\n",
326                                 depth);
327                 else if (m)
328                         printf("%3d: warning: too many params in next recv\n",
329                                 depth);
330         }
331
332         /* set the fields */
333         if (Rvous)
334         {       n_rem = n;
335                 q_rem = q;
336         }
337
338         oi = q->stepnr[i];
339         for (m = n->rgt, j = 0; m && j < q->nflds; m = m->rgt, j++)
340         {       if (columns && !full)   /* was columns == 1 */
341                         continue;
342                 if ((verbose&8) && !Rvous && depth >= jumpsteps)
343                 {       sr_talk(n, q->contents[i*q->nflds+j],
344                         (full && n->val < 2)?"Recv ":"[Recv] ", "<-", j, q);
345                 }
346                 if (!full)
347                         continue;       /* test */
348                 if (m && m->lft->ntyp != CONST && m->lft->ntyp != EVAL)
349                 {       (void) setval(m->lft, q->contents[i*q->nflds+j]);
350                         typ_ck(q->fld_width[j], Sym_typ(m->lft), "recv");
351                 }
352                 if (n->val < 2)         /* not a poll */
353                 for (k = i; k < q->qlen-1; k++)
354                 {       q->contents[k*q->nflds+j] =
355                           q->contents[(k+1)*q->nflds+j];
356                         if (j == 0)
357                           q->stepnr[k] = q->stepnr[k+1];
358                 }
359         }
360
361         if ((!columns || full)
362         && (verbose&8) && !Rvous && depth >= jumpsteps)
363         for (i = j; i < q->nflds; i++)
364         {       sr_talk(n, 0,
365                 (full && n->val < 2)?"Recv ":"[Recv] ", "<-", i, q);
366         }
367         if (columns == 2 && full && !Rvous && depth >= jumpsteps)
368                 putarrow(oi, depth);
369
370         if (full && n->val < 2)
371                 q->qlen--;
372         return 1;
373 }
374
375 static int
376 s_snd(Queue *q, Lextok *n)
377 {       Lextok *m;
378         RunList *rX, *sX = X;   /* rX=recvr, sX=sendr */
379         int i, j = 0;   /* q field# */
380
381         for (m = n->rgt; m && j < q->nflds; m = m->rgt, j++)
382         {       q->contents[j] = cast_val(q->fld_width[j], eval(m->lft), 0);
383                 typ_ck(q->fld_width[j], Sym_typ(m->lft), "rv-send");
384         }
385         q->qlen = 1;
386         if (!complete_rendez())
387         {       q->qlen = 0;
388                 return 0;
389         }
390         if (TstOnly)
391         {       q->qlen = 0;
392                 return 1;
393         }
394         q->stepnr[0] = depth;
395         if ((verbose&16) && depth >= jumpsteps)
396         {       m = n->rgt;
397                 rX = X; X = sX;
398                 for (j = 0; m && j < q->nflds; m = m->rgt, j++)
399                         sr_talk(n, eval(m->lft), "Sent ", "->", j, q);
400                 for (i = j; i < q->nflds; i++)
401                         sr_talk(n, 0, "Sent ", "->", i, q);
402                 if (j < q->nflds)
403                           printf("%3d: warning: missing params in rv-send\n",
404                                 depth);
405                 else if (m)
406                           printf("%3d: warning: too many params in rv-send\n",
407                                 depth);
408                 X = rX; /* restore receiver's context */
409                 if (!s_trail)
410                 {       if (!n_rem || !q_rem)
411                                 fatal("cannot happen, s_snd", (char *) 0);
412                         m = n_rem->rgt;
413                         for (j = 0; m && j < q->nflds; m = m->rgt, j++)
414                         {       if (m->lft->ntyp != NAME
415                                 ||  strcmp(m->lft->sym->name, "_") != 0)
416                                         i = eval(m->lft);
417                                 else    i = 0;
418
419                                 if (verbose&8)
420                                 sr_talk(n_rem,i,"Recv ","<-",j,q_rem);
421                         }
422                         if (verbose&8)
423                         for (i = j; i < q->nflds; i++)
424                                 sr_talk(n_rem, 0, "Recv ", "<-", j, q_rem);
425                         if (columns == 2)
426                                 putarrow(depth, depth);
427                 }
428                 n_rem = (Lextok *) 0;
429                 q_rem = (Queue *) 0;
430         }
431         return 1;
432 }
433
434 static void
435 channm(Lextok *n)
436 {       char lbuf[512];
437
438         if (n->sym->type == CHAN)
439                 strcat(Buf, n->sym->name);
440         else if (n->sym->type == NAME)
441                 strcat(Buf, lookup(n->sym->name)->name);
442         else if (n->sym->type == STRUCT)
443         {       Symbol *r = n->sym;
444                 if (r->context)
445                 {       r = findloc(r);
446                         if (!r)
447                         {       strcat(Buf, "*?*");
448                                 return;
449                 }       }
450                 ini_struct(r);
451                 printf("%s", r->name);
452                 strcpy(lbuf, "");
453                 struct_name(n->lft, r, 1, lbuf);
454                 strcat(Buf, lbuf);
455         } else
456                 strcat(Buf, "-");
457         if (n->lft->lft)
458         {       sprintf(lbuf, "[%d]", eval(n->lft->lft));
459                 strcat(Buf, lbuf);
460         }
461 }
462
463 static void
464 difcolumns(Lextok *n, char *tr, int v, int j, Queue *q)
465 {       extern int pno;
466
467         if (j == 0)
468         {       Buf[0] = '\0';
469                 channm(n);
470                 strcat(Buf, (strncmp(tr, "Sen", 3))?"?":"!");
471         } else
472                 strcat(Buf, ",");
473         if (tr[0] == '[') strcat(Buf, "[");
474         sr_buf(v, q->fld_width[j] == MTYPE);
475         if (j == q->nflds - 1)
476         {       int cnr;
477                 if (s_trail)
478                 {       cnr = pno;
479                 } else
480                 {       cnr = X?X->pid - Have_claim:0;
481                 }
482                 if (tr[0] == '[') strcat(Buf, "]");
483                 pstext(cnr, Buf);
484         }
485 }
486
487 static void
488 docolumns(Lextok *n, char *tr, int v, int j, Queue *q)
489 {       int i;
490
491         if (firstrow)
492         {       printf("q\\p");
493                 for (i = 0; i < nproc-nstop - Have_claim; i++)
494                         printf(" %3d", i);
495                 printf("\n");
496                 firstrow = 0;
497         }
498         if (j == 0)
499         {       printf("%3d", q->qid);
500                 if (X)
501                 for (i = 0; i < X->pid - Have_claim; i++)
502                         printf("   .");
503                 printf("   ");
504                 Buf[0] = '\0';
505                 channm(n);
506                 printf("%s%c", Buf, (strncmp(tr, "Sen", 3))?'?':'!');
507         } else
508                 printf(",");
509         if (tr[0] == '[') printf("[");
510         sr_mesg(stdout, v, q->fld_width[j] == MTYPE);
511         if (j == q->nflds - 1)
512         {       if (tr[0] == '[') printf("]");
513                 printf("\n");
514         }
515 }
516
517 void
518 qhide(int q)
519 {       QH *p = (QH *) emalloc(sizeof(QH));
520         p->n = q;
521         p->nxt = qh;
522         qh = p;
523 }
524
525 int
526 qishidden(int q)
527 {       QH *p;
528         for (p = qh; p; p = p->nxt)
529                 if (p->n == q)
530                         return 1;
531         return 0;
532 }
533
534 static void
535 sr_talk(Lextok *n, int v, char *tr, char *a, int j, Queue *q)
536 {       char s[128];
537
538         if (qishidden(eval(n->lft)))
539                 return;
540
541         if (columns)
542         {       if (columns == 2)
543                         difcolumns(n, tr, v, j, q);
544                 else
545                         docolumns(n, tr, v, j, q);
546                 return;
547         }
548         if (xspin)
549         {       if ((verbose&4) && tr[0] != '[')
550                 sprintf(s, "(state -)\t[values: %d",
551                         eval(n->lft));
552                 else
553                 sprintf(s, "(state -)\t[%d", eval(n->lft));
554                 if (strncmp(tr, "Sen", 3) == 0)
555                         strcat(s, "!");
556                 else
557                         strcat(s, "?");
558         } else
559         {       strcpy(s, tr);
560         }
561
562         if (j == 0)
563         {       char snm[128];
564                 whoruns(1);
565                 {       char *ptr = n->fn->name;
566                         char *qtr = snm;
567                         while (*ptr != '\0')
568                         {       if (*ptr != '\"')
569                                 {       *qtr++ = *ptr;
570                                 }
571                                 ptr++;
572                         }
573                         *qtr = '\0';
574                         printf("%s:%d %s",
575                                 snm, n->ln, s);
576                 }
577         } else
578                 printf(",");
579         sr_mesg(stdout, v, q->fld_width[j] == MTYPE);
580
581         if (j == q->nflds - 1)
582         {       if (xspin)
583                 {       printf("]\n");
584                         if (!(verbose&4)) printf("\n");
585                         return;
586                 }
587                 printf("\t%s queue %d (", a, eval(n->lft));
588                 Buf[0] = '\0';
589                 channm(n);
590                 printf("%s)\n", Buf);
591         }
592         fflush(stdout);
593 }
594
595 void
596 sr_buf(int v, int j)
597 {       int cnt = 1; Lextok *n;
598         char lbuf[512];
599
600         for (n = Mtype; n && j; n = n->rgt, cnt++)
601                 if (cnt == v)
602                 {       if(strlen(n->lft->sym->name) >= sizeof(lbuf))
603                         {       non_fatal("mtype name %s too long", n->lft->sym->name);
604                                 break;
605                         }
606                         sprintf(lbuf, "%s", n->lft->sym->name);
607                         strcat(Buf, lbuf);
608                         return;
609                 }
610         sprintf(lbuf, "%d", v);
611         strcat(Buf, lbuf);
612 }
613
614 void
615 sr_mesg(FILE *fd, int v, int j)
616 {       Buf[0] ='\0';
617         sr_buf(v, j);
618 #if 1
619         fprintf(fd, Buf, (char *) 0); /* prevent compiler warning */
620 #else
621         fprintf(fd, Buf);
622 #endif
623 }
624
625 void
626 doq(Symbol *s, int n, RunList *r)
627 {       Queue *q;
628         int j, k;
629
630         if (!s->val)    /* uninitialized queue */
631                 return;
632         for (q = qtab; q; q = q->nxt)
633         if (q->qid == s->val[n])
634         {       if (xspin > 0
635                 && (verbose&4)
636                 && q->setat < depth)
637                         continue;
638                 if (q->nslots == 0)
639                         continue; /* rv q always empty */
640 #if 0
641                 if (q->qlen == 0)       /* new 7/10 -- dont show if queue is empty */
642                 {       continue;
643                 }
644 #endif
645                 printf("\t\tqueue %d (", q->qid);
646                 if (r)
647                 printf("%s(%d):", r->n->name, r->pid - Have_claim);
648                 if (s->nel > 1 || s->isarray)
649                   printf("%s[%d]): ", s->name, n);
650                 else
651                   printf("%s): ", s->name);
652                 for (k = 0; k < q->qlen; k++)
653                 {       printf("[");
654                         for (j = 0; j < q->nflds; j++)
655                         {       if (j > 0) printf(",");
656                                 sr_mesg(stdout, q->contents[k*q->nflds+j],
657                                         q->fld_width[j] == MTYPE);
658                         }
659                         printf("]");
660                 }
661                 printf("\n");
662                 break;
663         }
664 }
665
666 void
667 nochan_manip(Lextok *p, Lextok *n, int d)
668 {       int e = 1;
669
670         if (d == 0 && p->sym && p->sym->type == CHAN)
671         {       setaccess(p->sym, ZS, 0, 'L');
672
673                 if (n && n->ntyp == CONST)
674                         fatal("invalid asgn to chan", (char *) 0);
675
676                 if (n && n->sym && n->sym->type == CHAN)
677                 {       setaccess(n->sym, ZS, 0, 'V');
678                         return;
679                 }       
680         }
681
682         /* ok on the rhs of an assignment: */
683         if (!n || n->ntyp == LEN || n->ntyp == RUN
684         ||  n->ntyp == FULL  || n->ntyp == NFULL
685         ||  n->ntyp == EMPTY || n->ntyp == NEMPTY
686         ||  n->ntyp == 'R')
687                 return;
688
689         if (n->sym && n->sym->type == CHAN)
690         {       if (d == 1)
691                         fatal("invalid use of chan name", (char *) 0);
692                 else
693                         setaccess(n->sym, ZS, 0, 'V');  
694         }
695
696         if (n->ntyp == NAME
697         ||  n->ntyp == '.')
698                 e = 0;  /* array index or struct element */
699
700         nochan_manip(p, n->lft, e);
701         nochan_manip(p, n->rgt, 1);
702 }
703
704 typedef struct BaseName {
705         char *str;
706         int cnt;
707         struct BaseName *nxt;
708 } BaseName;
709
710 static BaseName *bsn;
711
712 void
713 newbasename(char *s)
714 {       BaseName *b;
715
716 /*      printf("+++++++++%s\n", s);     */
717         for (b = bsn; b; b = b->nxt)
718                 if (strcmp(b->str, s) == 0)
719                 {       b->cnt++;
720                         return;
721                 }
722         b = (BaseName *) emalloc(sizeof(BaseName));
723         b->str = emalloc(strlen(s)+1);
724         b->cnt = 1;
725         strcpy(b->str, s);
726         b->nxt = bsn;
727         bsn = b;
728 }
729
730 void
731 delbasename(char *s)
732 {       BaseName *b, *prv = (BaseName *) 0;
733
734         for (b = bsn; b; prv = b, b = b->nxt)
735         {       if (strcmp(b->str, s) == 0)
736                 {       b->cnt--;
737                         if (b->cnt == 0)
738                         {       if (prv)
739                                 {       prv->nxt = b->nxt;
740                                 } else
741                                 {       bsn = b->nxt;
742                         }       }
743 /*      printf("---------%s\n", s);     */
744                         break;
745         }       }
746 }
747
748 void
749 checkindex(char *s, char *t)
750 {       BaseName *b;
751
752 /*      printf("xxx Check %s (%s)\n", s, t);    */
753         for (b = bsn; b; b = b->nxt)
754         {
755 /*              printf("        %s\n", b->str); */
756                 if (strcmp(b->str, s) == 0)
757                 {       non_fatal("do not index an array with itself (%s)", t);
758                         break;
759         }       }
760 }
761
762 void
763 scan_tree(Lextok *t, char *mn, char *mx)
764 {       char sv[512];
765         char tmp[32];
766         int oln = lineno;
767
768         if (!t) return;
769
770         lineno = t->ln;
771
772         if (t->ntyp == NAME)
773         {       strcat(mn, t->sym->name);
774                 strcat(mx, t->sym->name);
775                 if (t->lft)             /* array index */
776                 {       strcat(mn, "[]");
777                         newbasename(mn);
778                                 strcpy(sv, mn);         /* save */
779                                 strcpy(mn, "");         /* clear */
780                                 strcat(mx, "[");
781                                 scan_tree(t->lft, mn, mx);      /* index */
782                                 strcat(mx, "]");
783                                 checkindex(mn, mx);     /* match against basenames */
784                                 strcpy(mn, sv);         /* restore */
785                         delbasename(mn);
786                 }
787                 if (t->rgt)     /* structure element */
788                 {       scan_tree(t->rgt, mn, mx);
789                 }
790         } else if (t->ntyp == CONST)
791         {       strcat(mn, "1"); /* really: t->val */
792                 sprintf(tmp, "%d", t->val);
793                 strcat(mx, tmp);
794         } else if (t->ntyp == '.')
795         {       strcat(mn, ".");
796                 strcat(mx, ".");
797                 scan_tree(t->lft, mn, mx);
798         } else
799         {       strcat(mn, "??");
800                 strcat(mx, "??");
801         }
802         lineno = oln;
803 }
804
805 void
806 no_nested_array_refs(Lextok *n) /* a [ a[1] ] with a[1] = 1, causes trouble in pan.b */
807 {       char mn[512];
808         char mx[512];
809
810 /*      printf("==================================ZAP\n");      */
811         bsn = (BaseName *) 0;   /* start new list */
812         strcpy(mn, "");
813         strcpy(mx, "");
814
815         scan_tree(n, mn, mx);
816 /*      printf("==> %s\n", mn); */
817 }
818
819 void
820 no_internals(Lextok *n)
821 {       char *sp;
822
823         if (!n->sym
824         ||  !n->sym->name)
825                 return;
826
827         sp = n->sym->name;
828
829         if ((strlen(sp) == strlen("_nr_pr") && strcmp(sp, "_nr_pr") == 0)
830         ||  (strlen(sp) == strlen("_pid") && strcmp(sp, "_pid") == 0)
831         ||  (strlen(sp) == strlen("_p") && strcmp(sp, "_p") == 0))
832         {       fatal("invalid assignment to %s", sp);
833         }
834
835         no_nested_array_refs(n);
836 }