]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - release/picobsd/tinyware/msh/sh1.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / release / picobsd / tinyware / msh / sh1.c
1 #define Extern extern
2 #include <sys/types.h>
3 #include <signal.h>
4 #define _NSIG NSIG
5 #include <errno.h>
6 #include <setjmp.h>
7 #include "sh.h"
8 /* -------- sh.c -------- */
9 /*
10  * shell
11  */
12
13 /* #include "sh.h" */
14
15 int     intr;
16 int     inparse;
17 char    flags['z'-'a'+1];
18 char    *flag = flags-'a';
19 char    *elinep = line+sizeof(line)-5;
20 char    *null   = "";
21 int     heedint =1;
22 struct  env     e ={line, iostack, iostack-1,
23                     (xint *)NULL, FDBASE, (struct env *)NULL};
24
25 extern  char    **environ;      /* environment pointer */
26
27 /*
28  * default shell, search rules
29  */
30 char    shellname[] = "/bin/sh";
31 char    search[] = ":/bin:/usr/bin";
32
33 _PROTOTYPE(void (*qflag), (int)) = SIG_IGN;
34
35 _PROTOTYPE(int main, (int argc, char **argv ));
36 _PROTOTYPE(int newfile, (char *s ));
37 _PROTOTYPE(static char *findeq, (char *cp ));
38 _PROTOTYPE(static char *cclass, (char *p, int sub ));
39 _PROTOTYPE(void initarea, (void));
40
41 int main(argc, argv)
42 int argc;
43 register char **argv;
44 {
45         register int f;
46         register char *s;
47         int cflag;
48         char *name, **ap;
49         int (*iof)();
50
51         initarea();
52         if ((ap = environ) != NULL) {
53                 while (*ap)
54                         assign(*ap++, !COPYV);
55                 for (ap = environ; *ap;)
56                         export(lookup(*ap++));
57         }
58         closeall();
59         areanum = 1;
60
61         shell = lookup("SHELL");
62         if (shell->value == null)
63                 setval(shell, shellname);
64         export(shell);
65
66         homedir = lookup("HOME");
67         if (homedir->value == null)
68                 setval(homedir, "/");
69         export(homedir);
70
71         setval(lookup("$"), itoa(getpid(), 5));
72
73         path = lookup("PATH");
74         if (path->value == null)
75                 setval(path, search);
76         export(path);
77
78         ifs = lookup("IFS");
79         if (ifs->value == null)
80                 setval(ifs, " \t\n");
81
82         prompt = lookup("PS1");
83         if (prompt->value == null)
84 #ifndef UNIXSHELL
85                 setval(prompt, "$ ");
86 #else
87                 setval(prompt, "% ");
88 #endif
89
90         if (geteuid() == 0) {
91                 setval(prompt, "# ");
92                 prompt->status &= ~EXPORT;
93         }
94         cprompt = lookup("PS2");
95         if (cprompt->value == null)
96                 setval(cprompt, "> ");
97
98         iof = filechar;
99         cflag = 0;
100         name = *argv++;
101         if (--argc >= 1) {
102                 if(argv[0][0] == '-' && argv[0][1] != '\0') {
103                         for (s = argv[0]+1; *s; s++)
104                                 switch (*s) {
105                                 case 'c':
106                                         prompt->status &= ~EXPORT;
107                                         cprompt->status &= ~EXPORT;
108                                         setval(prompt, "");
109                                         setval(cprompt, "");
110                                         cflag = 1;
111                                         if (--argc > 0)
112                                                 PUSHIO(aword, *++argv, iof = nlchar);
113                                         break;
114         
115                                 case 'q':
116                                         qflag = SIG_DFL;
117                                         break;
118
119                                 case 's':
120                                         /* standard input */
121                                         break;
122
123                                 case 't':
124                                         prompt->status &= ~EXPORT;
125                                         setval(prompt, "");
126                                         iof = linechar;
127                                         break;
128         
129                                 case 'i':
130                                         talking++;
131                                 default:
132                                         if (*s>='a' && *s<='z')
133                                                 flag[*s]++;
134                                 }
135                 } else {
136                         argv--;
137                         argc++;
138                 }
139                 if (iof == filechar && --argc > 0) {
140                         setval(prompt, "");
141                         setval(cprompt, "");
142                         prompt->status &= ~EXPORT;
143                         cprompt->status &= ~EXPORT;
144                         if (newfile(name = *++argv))
145                                 exit(1);
146                 }
147         }
148         setdash();
149         if (e.iop < iostack) {
150                 PUSHIO(afile, 0, iof);
151                 if (isatty(0) && isatty(1) && !cflag)
152                         talking++;
153         }
154         signal(SIGQUIT, qflag);
155         if (name && name[0] == '-') {
156                 talking++;
157                 if ((f = open(".profile", 0)) >= 0)
158                         next(remap(f));
159                 if ((f = open("/etc/profile", 0)) >= 0)
160                         next(remap(f));
161         }
162         if (talking)
163                 signal(SIGTERM, sig);
164         if (signal(SIGINT, SIG_IGN) != SIG_IGN)
165                 signal(SIGINT, onintr);
166         dolv = argv;
167         dolc = argc;
168         dolv[0] = name;
169         if (dolc > 1)
170                 for (ap = ++argv; --argc > 0;)
171                         if (assign(*ap = *argv++, !COPYV))
172                                 dolc--; /* keyword */
173                         else
174                                 ap++;
175         setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
176
177         for (;;) {
178                 if (talking && e.iop <= iostack)
179                         prs(prompt->value);
180                 onecommand();
181         }
182 }
183
184 void
185 setdash()
186 {
187         register char *cp, c;
188         char m['z'-'a'+1];
189
190         cp = m;
191         for (c='a'; c<='z'; c++)
192                 if (flag[c])
193                         *cp++ = c;
194         *cp = 0;
195         setval(lookup("-"), m);
196 }
197
198 int
199 newfile(s)
200 register char *s;
201 {
202         register f;
203
204         if (strcmp(s, "-") != 0) {
205                 f = open(s, 0);
206                 if (f < 0) {
207                         prs(s);
208                         err(": cannot open");
209                         return(1);
210                 }
211         } else
212                 f = 0;
213         next(remap(f));
214         return(0);
215 }
216
217 void
218 onecommand()
219 {
220         register i;
221         jmp_buf m1;
222
223         while (e.oenv)
224                 quitenv();
225         areanum = 1;
226         freehere(areanum);
227         freearea(areanum);
228         garbage();
229         wdlist = 0;
230         iolist = 0;
231         e.errpt = 0;
232         e.linep = line;
233         yynerrs = 0;
234         multiline = 0;
235         inparse = 1;
236         intr = 0;
237         execflg = 0;
238         setjmp(failpt = m1);    /* Bruce Evans' fix */
239         if (setjmp(failpt = m1) || yyparse() || intr) {
240                 while (e.oenv)
241                         quitenv();
242                 scraphere();
243                 if (!talking && intr)
244                         leave();
245                 inparse = 0;
246                 intr = 0;
247                 return;
248         }
249         inparse = 0;
250         brklist = 0;
251         intr = 0;
252         execflg = 0;
253         if (!flag['n'])
254                 execute(outtree, NOPIPE, NOPIPE, 0);
255         if (!talking && intr) {
256                 execflg = 0;
257                 leave();
258         }
259         if ((i = trapset) != 0) {
260                 trapset = 0;
261                 runtrap(i);
262         }
263 }
264
265 void
266 fail()
267 {
268         longjmp(failpt, 1);
269         /* NOTREACHED */
270 }
271
272 void
273 leave()
274 {
275         if (execflg)
276                 fail();
277         scraphere();
278         freehere(1);
279         runtrap(0);
280         exit(exstat);
281         /* NOTREACHED */
282 }
283
284 void
285 warn(s)
286 register char *s;
287 {
288         if(*s) {
289                 prs(s);
290                 exstat = -1;
291         }
292         prs("\n");
293         if (flag['e'])
294                 leave();
295 }
296
297 void
298 err(s)
299 char *s;
300 {
301         warn(s);
302         if (flag['n'])
303                 return;
304         if (!talking)
305                 leave();
306         if (e.errpt)
307                 longjmp(e.errpt, 1);
308         closeall();
309         e.iop = e.iobase = iostack;
310 }
311
312 int
313 newenv(f)
314 int f;
315 {
316         register struct env *ep;
317
318         if (f) {
319                 quitenv();
320                 return(1);
321         }
322         ep = (struct env *) space(sizeof(*ep));
323         if (ep == NULL) {
324                 while (e.oenv)
325                         quitenv();
326                 fail();
327         }
328         *ep = e;
329         e.oenv = ep;
330         e.errpt = errpt;
331         return(0);
332 }
333
334 void
335 quitenv()
336 {
337         register struct env *ep;
338         register fd;
339
340         if ((ep = e.oenv) != NULL) {
341                 fd = e.iofd;
342                 e = *ep;
343                 /* should close `'d files */
344                 DELETE(ep);
345                 while (--fd >= e.iofd)
346                         close(fd);
347         }
348 }
349
350 /*
351  * Is any character from s1 in s2?
352  */
353 int
354 anys(s1, s2)
355 register char *s1, *s2;
356 {
357         while (*s1)
358                 if (any(*s1++, s2))
359                         return(1);
360         return(0);
361 }
362
363 /*
364  * Is character c in s?
365  */
366 int
367 any(c, s)
368 register int c;
369 register char *s;
370 {
371         while (*s)
372                 if (*s++ == c)
373                         return(1);
374         return(0);
375 }
376
377 char *
378 putn(n)
379 register int n;
380 {
381         return(itoa(n, -1));
382 }
383
384 char *
385 itoa(u, n)
386 register unsigned u;
387 int n;
388 {
389         register char *cp;
390         static char s[20];
391         int m;
392
393         m = 0;
394         if (n < 0 && (int) u < 0) {
395                 m++;
396                 u = -u;
397         }
398         cp = s+sizeof(s);
399         *--cp = 0;
400         do {
401                 *--cp = u%10 + '0';
402                 u /= 10;
403         } while (--n > 0 || u);
404         if (m)
405                 *--cp = '-';
406         return(cp);
407 }
408
409 void
410 next(f)
411 int f;
412 {
413         PUSHIO(afile, f, filechar);
414 }
415
416 void
417 onintr(s)
418 int s;                          /* ANSI C requires a parameter */
419 {
420         signal(SIGINT, onintr);
421         intr = 1;
422         if (talking) {
423                 if (inparse) {
424                         prs("\n");
425                         fail();
426                 }
427         }
428         else if (heedint) {
429                 execflg = 0;
430                 leave();
431         }
432 }
433
434 int
435 letter(c)
436 register c;
437 {
438         return((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
439 }
440
441 int
442 digit(c)
443 register c;
444 {
445         return(c >= '0' && c <= '9');
446 }
447
448 int
449 letnum(c)
450 register c;
451 {
452         return(letter(c) || digit(c));
453 }
454
455 char *
456 space(n)
457 int n;
458 {
459         register char *cp;
460
461         if ((cp = getcell(n)) == 0)
462                 err("out of string space");
463         return(cp);
464 }
465
466 char *
467 strsave(s, a)
468 register char *s;
469 int a;
470 {
471         register char *cp, *xp;
472
473         if ((cp = space(strlen(s)+1)) != NULL) {
474                 setarea((char *)cp, a);
475                 for (xp = cp; (*xp++ = *s++) != '\0';)
476                         ;
477                 return(cp);
478         }
479         return("");
480 }
481
482 void
483 xfree(s)
484 register char *s;
485 {
486         DELETE(s);
487 }
488
489 /*
490  * trap handling
491  */
492 void
493 sig(i)
494 register int i;
495 {
496         trapset = i;
497         signal(i, sig);
498 }
499
500 void runtrap(i)
501 int i;
502 {
503         char *trapstr;
504
505         if ((trapstr = trap[i]) == NULL)
506                 return;
507         if (i == 0)
508                 trap[i] = 0;
509         RUN(aword, trapstr, nlchar);
510 }
511
512 /* -------- var.c -------- */
513 /* #include "sh.h" */
514
515 /*
516  * Find the given name in the dictionary
517  * and return its value.  If the name was
518  * not previously there, enter it now and
519  * return a null value.
520  */
521 struct var *
522 lookup(n)
523 register char *n;
524 {
525         register struct var *vp;
526         register char *cp;
527         register int c;
528         static struct var dummy;
529
530         if (digit(*n)) {
531                 dummy.name = n;
532                 for (c = 0; digit(*n) && c < 1000; n++)
533                         c = c*10 + *n-'0';
534                 dummy.status = RONLY;
535                 dummy.value = c <= dolc? dolv[c]: null;
536                 return(&dummy);
537         }
538         for (vp = vlist; vp; vp = vp->next)
539                 if (eqname(vp->name, n))
540                         return(vp);
541         cp = findeq(n);
542         vp = (struct var *)space(sizeof(*vp));
543         if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) {
544                 dummy.name = dummy.value = "";
545                 return(&dummy);
546         }
547         for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++)
548                 ;
549         if (*cp == 0)
550                 *cp = '=';
551         *++cp = 0;
552         setarea((char *)vp, 0);
553         setarea((char *)vp->name, 0);
554         vp->value = null;
555         vp->next = vlist;
556         vp->status = GETCELL;
557         vlist = vp;
558         return(vp);
559 }
560
561 /*
562  * give variable at `vp' the value `val'.
563  */
564 void
565 setval(vp, val)
566 struct var *vp;
567 char *val;
568 {
569         nameval(vp, val, (char *)NULL);
570 }
571
572 /*
573  * if name is not NULL, it must be
574  * a prefix of the space `val',
575  * and end with `='.
576  * this is all so that exporting
577  * values is reasonably painless.
578  */
579 void
580 nameval(vp, val, name)
581 register struct var *vp;
582 char *val, *name;
583 {
584         register char *cp, *xp;
585         char *nv;
586         int fl;
587
588         if (vp->status & RONLY) {
589                 for (xp = vp->name; *xp && *xp != '=';)
590                         putc(*xp++);
591                 err(" is read-only");
592                 return;
593         }
594         fl = 0;
595         if (name == NULL) {
596                 xp = space(strlen(vp->name)+strlen(val)+2);
597                 if (xp == 0)
598                         return;
599                 /* make string:  name=value */
600                 setarea((char *)xp, 0);
601                 name = xp;
602                 for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++)
603                         ;
604                 if (*xp++ == 0)
605                         xp[-1] = '=';
606                 nv = xp;
607                 for (cp = val; (*xp++ = *cp++) != '\0';)
608                         ;
609                 val = nv;
610                 fl = GETCELL;
611         }
612         if (vp->status & GETCELL)
613                 xfree(vp->name);        /* form new string `name=value' */
614         vp->name = name;
615         vp->value = val;
616         vp->status |= fl;
617 }
618
619 void
620 export(vp)
621 struct var *vp;
622 {
623         vp->status |= EXPORT;
624 }
625
626 void
627 ronly(vp)
628 struct var *vp;
629 {
630         if (letter(vp->name[0]))        /* not an internal symbol ($# etc) */
631                 vp->status |= RONLY;
632 }
633
634 int
635 isassign(s)
636 register char *s;
637 {
638         if (!letter((int)*s))
639                 return(0);
640         for (; *s != '='; s++)
641                 if (*s == 0 || !letnum(*s))
642                         return(0);
643         return(1);
644 }
645
646 int
647 assign(s, cf)
648 register char *s;
649 int cf;
650 {
651         register char *cp;
652         struct var *vp;
653
654         if (!letter(*s))
655                 return(0);
656         for (cp = s; *cp != '='; cp++)
657                 if (*cp == 0 || !letnum(*cp))
658                         return(0);
659         vp = lookup(s);
660         nameval(vp, ++cp, cf == COPYV? (char *)NULL: s);
661         if (cf != COPYV)
662                 vp->status &= ~GETCELL;
663         return(1);
664 }
665
666 int
667 checkname(cp)
668 register char *cp;
669 {
670         if (!letter(*cp++))
671                 return(0);
672         while (*cp)
673                 if (!letnum(*cp++))
674                         return(0);
675         return(1);
676 }
677
678 void
679 putvlist(f, out)
680 register int f, out;
681 {
682         register struct var *vp;
683
684         for (vp = vlist; vp; vp = vp->next)
685                 if (vp->status & f && letter(*vp->name)) {
686                         if (vp->status & EXPORT)
687                                 write(out, "export ", 7);
688                         if (vp->status & RONLY)
689                                 write(out, "readonly ", 9);
690                         write(out, vp->name, (int)(findeq(vp->name) - vp->name));
691                         write(out, "\n", 1);
692                 }
693 }
694
695 int
696 eqname(n1, n2)
697 register char *n1, *n2;
698 {
699         for (; *n1 != '=' && *n1 != 0; n1++)
700                 if (*n2++ != *n1)
701                         return(0);
702         return(*n2 == 0 || *n2 == '=');
703 }
704
705 static char *
706 findeq(cp)
707 register char *cp;
708 {
709         while (*cp != '\0' && *cp != '=')
710                 cp++;
711         return(cp);
712 }
713
714 /* -------- gmatch.c -------- */
715 /*
716  * int gmatch(string, pattern)
717  * char *string, *pattern;
718  *
719  * Match a pattern as in sh(1).
720  */
721
722 #define CMASK   0377
723 #define QUOTE   0200
724 #define QMASK   (CMASK&~QUOTE)
725 #define NOT     '!'     /* might use ^ */
726
727 int
728 gmatch(s, p)
729 register char *s, *p;
730 {
731         register int sc, pc;
732
733         if (s == NULL || p == NULL)
734                 return(0);
735         while ((pc = *p++ & CMASK) != '\0') {
736                 sc = *s++ & QMASK;
737                 switch (pc) {
738                 case '[':
739                         if ((p = cclass(p, sc)) == NULL)
740                                 return(0);
741                         break;
742
743                 case '?':
744                         if (sc == 0)
745                                 return(0);
746                         break;
747
748                 case '*':
749                         s--;
750                         do {
751                                 if (*p == '\0' || gmatch(s, p))
752                                         return(1);
753                         } while (*s++ != '\0');
754                         return(0);
755
756                 default:
757                         if (sc != (pc&~QUOTE))
758                                 return(0);
759                 }
760         }
761         return(*s == 0);
762 }
763
764 static char *
765 cclass(p, sub)
766 register char *p;
767 register int sub;
768 {
769         register int c, d, not, found;
770
771         if ((not = *p == NOT) != 0)
772                 p++;
773         found = not;
774         do {
775                 if (*p == '\0')
776                         return((char *)NULL);
777                 c = *p & CMASK;
778                 if (p[1] == '-' && p[2] != ']') {
779                         d = p[2] & CMASK;
780                         p++;
781                 } else
782                         d = c;
783                 if (c == sub || (c <= sub && sub <= d))
784                         found = !not;
785         } while (*++p != ']');
786         return(found? p+1: (char *)NULL);
787 }
788
789 /* -------- area.c -------- */
790 #define REGSIZE         sizeof(struct region)
791 #define GROWBY          256
792 #undef  SHRINKBY        64
793 #define FREE 32767
794 #define BUSY 0
795 #define ALIGN (sizeof(int)-1)
796
797 /* #include "area.h" */
798
799 struct region {
800         struct  region *next;
801         int     area;
802 };
803
804 /*
805  * All memory between (char *)areabot and (char *)(areatop+1) is
806  * exclusively administered by the area management routines.
807  * It is assumed that sbrk() and brk() manipulate the high end.
808  */
809 static  struct region *areabot;         /* bottom of area */
810 static  struct region *areatop;         /* top of area */
811 static  struct region *areanxt;         /* starting point of scan */
812
813 void
814 initarea()
815 {
816         while ((int)sbrk(0) & ALIGN)
817                 sbrk(1);
818         areabot = (struct region *)sbrk(REGSIZE);
819         areabot->next = areabot;
820         areabot->area = BUSY;
821         areatop = areabot;
822         areanxt = areabot;
823 }
824
825 char *
826 getcell(nbytes)
827 unsigned nbytes;
828 {
829         register int nregio;
830         register struct region *p, *q;
831         register i;
832
833         if (nbytes == 0)
834                 abort();        /* silly and defeats the algorithm */
835         /*
836          * round upwards and add administration area
837          */
838         nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1;
839         for (p = areanxt;;) {
840                 if (p->area > areanum) {
841                         /*
842                          * merge free cells
843                          */
844                         while ((q = p->next)->area > areanum && q != areanxt)
845                                 p->next = q->next;
846                         /*
847                          * exit loop if cell big enough
848                          */
849                         if (q >= p + nregio)
850                                 goto found;
851                 }
852                 p = p->next;
853                 if (p == areanxt)
854                         break;
855         }
856         i = nregio >= GROWBY ? nregio : GROWBY;
857         p = (struct region *)sbrk(i * REGSIZE);
858         if (p == (struct region *)-1)
859                 return((char *)NULL);
860         p--;
861         if (p != areatop)
862                 abort();        /* allocated areas are contiguous */
863         q = p + i;
864         p->next = q;
865         p->area = FREE;
866         q->next = areabot;
867         q->area = BUSY;
868         areatop = q;
869 found:
870         /*
871          * we found a FREE area big enough, pointed to by 'p', and up to 'q'
872          */
873         areanxt = p + nregio;
874         if (areanxt < q) {
875                 /*
876                  * split into requested area and rest
877                  */
878                 if (areanxt+1 > q)
879                         abort();        /* insufficient space left for admin */
880                 areanxt->next = q;
881                 areanxt->area = FREE;
882                 p->next = areanxt;
883         }
884         p->area = areanum;
885         return((char *)(p+1));
886 }
887
888 void
889 freecell(cp)
890 char *cp;
891 {
892         register struct region *p;
893
894         if ((p = (struct region *)cp) != NULL) {
895                 p--;
896                 if (p < areanxt)
897                         areanxt = p;
898                 p->area = FREE;
899         }
900 }
901
902 void
903 freearea(a)
904 register int a;
905 {
906         register struct region *p, *top;
907
908         top = areatop;
909         for (p = areabot; p != top; p = p->next)
910                 if (p->area >= a)
911                         p->area = FREE;
912 }
913
914 void
915 setarea(cp,a)
916 char *cp;
917 int a;
918 {
919         register struct region *p;
920
921         if ((p = (struct region *)cp) != NULL)
922                 (p-1)->area = a;
923 }
924
925 int
926 getarea(cp)
927 char *cp;
928 {
929         return ((struct region*)cp-1)->area;
930 }
931
932 void
933 garbage()
934 {
935         register struct region *p, *q, *top;
936
937         top = areatop;
938         for (p = areabot; p != top; p = p->next) {
939                 if (p->area > areanum) {
940                         while ((q = p->next)->area > areanum)
941                                 p->next = q->next;
942                         areanxt = p;
943                 }
944         }
945 #ifdef SHRINKBY
946         if (areatop >= q + SHRINKBY && q->area > areanum) {
947                 brk((char *)(q+1));
948                 q->next = areabot;
949                 q->area = BUSY;
950                 areatop = q;
951         }
952 #endif
953 }