fix URL in specfile - rm svn-keywords
[comgt.git] / gcom.c
1 /*
2  *  gcom version 0.3 - 3G/GPRS datacard management utility
3  *
4  *  Copyright (C) 2003  Paul Hardwick <paul@peck.org>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  See gcom.doc for more configuration and usage information.
21  *
22  */
23  
24  /***************************************************************************
25 * $Id: gcom.c 10 2006-01-04 12:40:44Z paul $
26 * $HeadURL: http://10.0.0.4/svn/gcom/gcom.c $
27  ****************************************************************************/
28
29
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <signal.h>
34 #include <termio.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <sys/time.h>
39 #include <time.h>
40 #include <sys/types.h>
41 #include <sys/ioctl.h>
42 #include <sys/wait.h>
43 #include <sys/stat.h>
44 #include "gcom.h"
45
46 #define MAXLABELS 3000  /* Maximum number of labels */
47 #define MAXGOSUBS 128   /* Max depth */
48 #define STRINGL 1024    /* String lengths.  Also, max script line length */
49 #define MAXPATH 1024    /* Max filename length (less or equal to STRINGL) */
50 #define MAXTOKEN 20     /* Maximum token or label length */
51 #define GTDEVICE "/dev/modem"
52
53 #define BOOL unsigned char
54 #define NVARS 286       /* a-z, a0-z9 == 26*11 */
55
56 extern char *optarg;
57 extern int optind, opterr;
58 FILE *filep;
59 char *script;
60 int scriptspace;
61 BOOL ifres;
62 int lastpc,pc; /* program "counters" */
63 long resultcode=0; /* result code */
64 int ignorecase=1;  /* no case sensitivity */
65 BOOL comecho=0; /* echo what's comin' in */
66 BOOL high_speed=0;
67 long senddelay=0; /* 0/100th second character delay for sending */
68 long number;  /* For getonearg() returning an long */
69 char **label; /* Index of labels for goto and gosub */
70 int *labelpc; /* Positions of said labels in script */
71 int labels;   /* Number of labels found in script */
72 long intvars[NVARS]; /* [a-z][0-9] integer variables */
73 char string[STRINGL]; /* For getstring() returns and misc. use (misuse) */
74 char *stringvars[NVARS]; /* $[a-z][0-9] string variables */
75 char cspeed[10];  /* Ascii representation of baudrate */
76 int speed=B0; /* Set to B110, B150, B300,..., B38400 */
77 char device[MAXPATH]; /* Comm device.  May be "-" */
78 char token[MAXTOKEN];   /* For gettoken() returns */
79 char scriptfile[MAXPATH]; /* Script file name */
80 BOOL verbose=0; /* Log actions */
81 struct termio cons, stbuf, svbuf;  /* termios: svbuf=before, stbuf=while */
82 int comfd=0; /* Communication file descriptor.  Defaults to stdin. */
83 char msg[STRINGL]; /* Massage messages here */
84 int preturn,returns[MAXGOSUBS];
85 int clocal=0;
86 int parity=0, bits=CS8, stopbits=0;
87 unsigned long hstart,hset;
88 char NullString[]={ "" };
89 BOOL lastcharnl=1; /* Indicate that last char printed from getonebyte
90                                was a nl, so no new one is needed */
91
92
93 //"open com \"/dev/modem\"\nset com 38400n81\nset senddelay 0.05\nsend \"ATi^m\"\nget 2 \" ^m\" $s\nprint \"Response : \",$s,\"\\n\"\nget 2 \" ^m\" $s\nprint \"Response :\",$s,\"\\n\"\nget 2 \" ^m\" $s\nprint \"Response : \",$s,\"\\n\"\n\n";
94 /* Prototypes. */
95 unsigned long htime(void);
96 void dormir(unsigned long microsecs);
97 void dotestkey(void);
98 void ext(long xtc);
99 void vmsg(char *text);
100 void skipline(void);
101 void printwhere(void);
102 void writecom(char *text);
103 int getonebyte(void);
104 void dodump(void);
105 void serror(char *text, int exitcode);
106 void skipspaces(void);
107 void getopen(void);
108 void getclose(void);
109 int gettoken(void);
110 void skiptoken(void);
111 long getvalue(void);
112 void getcomma(void);
113 void gethardstring(void);
114 void getstring(void);
115 unsigned long getdvalue(void);
116 void dolet(void);
117 int dowaitquiet(void);
118 int dowaitfor(void);
119 BOOL getonoroff(void);
120 void setcom(void);
121 void doset(void);
122 void dogoto(void);
123 void dogosub(void);
124 unsigned char getonearg(void);
125 void doif(void);
126 int getindex(void);
127 int getintindex(void);
128 int getstringindex(void);
129 void doget(void);
130 void doprint(int channel);
131 void doclose(void);
132 void opendevice(void);
133 void doopen(void);
134 int doscript(void);
135
136 /* Returns hundreds of seconds */
137 unsigned long htime(void) {
138   struct timeval timenow;
139   gettimeofday(&timenow,NULL);
140   return(100L*(timenow.tv_sec-hstart)+(timenow.tv_usec)/10000L-hset);
141 }
142
143 /* I use select() 'cause CX/UX 6.2 doesn't have usleep().
144    On Linux, usleep() uses select() anyway.
145 */
146 void dormir(unsigned long microsecs) {
147   struct timeval timeout;
148   timeout.tv_sec=microsecs/1000000L;
149   timeout.tv_usec=microsecs-(timeout.tv_sec*1000000L);
150   select(1,0,0,0,&timeout);
151 }
152
153 /* Tests for ENTER key */
154 void dotestkey(void) {
155   fd_set fds;
156   struct timeval timeout;
157   timeout.tv_sec=0L;
158   timeout.tv_usec=10000L;
159   FD_ZERO(&fds);
160   FD_SET(0,&fds);  /* Prepare to select() from stdin */
161   resultcode=select(1,&fds,0,0,&timeout);
162   if(resultcode) getchar();
163 }
164
165 /* Exit after resetting terminal settings */
166 void ext(long xtc) {
167   ioctl(1, TCSETA, &cons);
168   exit(xtc);
169 }
170
171 /* Log message if verbose is on */
172 void vmsg(char *text) {
173   time_t t;
174   char *ct;
175   if(verbose) {
176     if(lastcharnl==0) {
177       fprintf(stderr,"\n");
178       lastcharnl=1;
179     }
180     t=time(0);
181     ct=ctime(&t);
182     fprintf(stderr,"gcom %c%c:%c%c:%c%c -> %s\n",
183             ct[11],ct[12],ct[14],ct[15],ct[17],ct[18],
184             text);
185   }
186 }
187
188 /* Skip to next statement */
189 void skipline(void) {
190   while(script[pc]!='\n' && script[pc]!=0) pc++;
191   if(script[pc]) pc++;
192 }
193
194 void printwhere(void) {
195   int a,b,c;
196   sprintf(msg,"@%04d ",pc);
197   a=pc;
198   skipline();
199   b=pc-1;
200   pc=a;
201   c=strlen(msg);
202   for(;a<b;a++) msg[c++]=script[a];
203   msg[c]=0;
204   vmsg(msg);
205 }
206
207 /* Write a null-terminated string to communication device */
208 void writecom(char *text) {
209   int res;
210   unsigned int a;
211   char ch;
212   for(a=0;a<strlen(text);a++) {
213     ch=text[a];
214     res=write(comfd,&ch,1);
215     if(senddelay) dormir(senddelay);
216     if(res!=1) {
217       serror("Could not write to COM device",1);
218     }
219   }
220 }
221
222 /* Gets a single byte from comm. device.  Return -1 if none avail. */
223 int getonebyte(void) {
224   fd_set rfds;
225   int res;
226   char ch;
227   comecho = 1;
228   struct timeval timeout;
229   timeout.tv_sec=0L;
230   timeout.tv_usec=10000;
231   FD_ZERO(&rfds);
232   FD_SET(comfd, &rfds);
233   res=select(comfd+1,&rfds,NULL,NULL,&timeout);
234   if(res) {
235     res=read(comfd,&ch,1);
236     if(res==1) {
237       if(comecho) {
238         if(ch=='\n') lastcharnl=1;
239         else {
240           if(ch!='\r') lastcharnl=0;
241         }
242         /*fputc(ch,stderr);*/
243       }
244       return(ch);
245     }
246   }
247   else {
248     return(-1); /* Nada. */
249   }
250   return(0);
251 }
252
253 void dodump(void) {
254   char lmsg[STRINGL];
255   int a,b,c;
256   c=verbose;
257   verbose=1;
258   sprintf(lmsg,"-- Integer variables --"); vmsg(lmsg);
259   for(a=0;a<26;a++) {
260     for(b=0;b<11;b++) {
261       if(intvars[b*26+a]) {
262         sprintf(lmsg,"   = %ld",intvars[b*26+a]);
263         lmsg[1]='a'+a;
264         lmsg[2]=' ';
265         if(b) lmsg[2]='0'+b-1;
266         vmsg(lmsg);
267       }
268     }
269   }
270   sprintf(lmsg,"-- String variables --"); vmsg(lmsg);
271   for(a=0;a<26;a++) {
272     for(b=0;b<11;b++) {
273       if(stringvars[b*26+a]!=NullString) {
274         sprintf(lmsg,"$  = \"%s\"",stringvars[b*26+a]);
275         lmsg[1]='a'+a;
276         lmsg[2]=' ';
277         if(b) lmsg[2]='0'+b-1;
278         vmsg(lmsg);
279       }
280     }
281   }
282   verbose=c;
283 }
284
285 /* Report script errors and quit */
286 void serror(char *text, int exitcode) {
287   int a,line;
288   char lmsg[STRINGL];
289   verbose=1;
290   //dodump();
291   vmsg("-- Error Report --");
292   a=pc;     
293   pc=lastpc;
294   //printwhere();
295   pc=a;
296   while(pc!=0 && (script[pc]==' ' || script[pc]=='\t')) pc--;
297   strcpy(lmsg,"----> ");
298   for(a=6;a<STRINGL;a++) lmsg[a]=' ';
299   for(a=0;a<pc-lastpc;a++) {
300     if(script[a+lastpc]=='\t') lmsg[a+8]='\t';
301   }
302   a+=6;
303   lmsg[a++]='^';
304   lmsg[a]=0;
305   vmsg(lmsg);
306   a=0; line=1;
307   while(a<pc) {
308     if(script[a++]=='\n') {
309       if(a<pc) line++;
310     }
311   }
312   sprintf(lmsg,"Error @%d, line %d, %s. (%d)\n",pc,line,text,exitcode);
313   vmsg(lmsg);
314   ext(exitcode);
315 }
316
317 void skipspaces(void) {
318   while(script[pc]==' ' || script[pc]=='\t' ) pc++;
319 }
320
321 void getopen(void) {
322   int a;
323   a=pc;
324   skipspaces();
325   if(script[pc++]!='(') {
326     pc=a;
327     serror("Function requires open parenthesis",5);
328   }
329 }
330
331 void getclose(void) {
332   int a;
333   a=pc;
334   skipspaces();
335   if(script[pc++]!=')') {
336     pc=a;
337     serror("Function requires close parenthesis",5);
338   }
339 }
340
341 void skiptoken(void) {
342   skipspaces();
343   while(script[pc]!=' ' && script[pc]!='\t' && script[pc]!='\n' ) pc++;
344   skipspaces();
345 }
346
347 /* Parse script[pc] to get next statement.  Resolve comments and labels... */
348 int gettoken(void) {
349   int tokenp=0;
350   skipspaces();
351   if(script[pc]=='=' || script[pc]=='<' || script[pc]=='>' || script[pc]=='!') {
352     token[0]=0;
353     while(script[pc]=='=' || script[pc]=='<' || script[pc]=='>' || script[pc]=='!') {
354       token[tokenp++]=script[pc++];
355     }
356     token[tokenp]=0;
357     return(0);
358   }
359   if(script[pc]=='#') {
360     strcpy(token,"rem");
361     pc++;
362     return(0);
363   }
364   if(script[pc]=='/' && script[pc+1]=='/') {
365     strcpy(token,"rem");
366     pc+=2;
367     return(0);
368   }
369   if(script[pc]==':') {
370     strcpy(token,"label");
371     pc++;
372     return(0);
373   }
374   while(script[pc]!=' ' && script[pc]!='\n' &&
375         script[pc]!='\t' && script[pc]!='(') {
376     token[tokenp]=script[pc++];
377     if(token[tokenp]>='A' && token[tokenp]<='Z') {
378       token[tokenp]=token[tokenp]-'A'+'a';
379     }
380     if(tokenp++==MAXTOKEN-1) serror("Token too long",5);
381   }
382   token[tokenp]=0;
383   if(strcmp(token,"then")==0) return(gettoken()); /* Ignore then for if */
384   return(0);
385 }
386
387 /* shitfaced recursive value parser. must write better one */
388 long getvalue(void) {
389   unsigned long p=0;
390   int goone=1;
391   unsigned int a;
392   int base,amode;
393   skipspaces();
394   if(script[pc]=='(') {
395     pc++;
396     p=getvalue();
397     getclose();
398   }
399   else if(script[pc]==')') {
400     return(p);
401   }
402   else if(script[pc]=='"' || script[pc]=='\'' || script[pc]=='$' ) {
403     serror("Did not expect a string",7);
404   }
405   else if( (script[pc]>='a' && script[pc]<='z' &&
406             script[pc+1]>='a' && script[pc+1]<='z') ||
407            (script[pc]>='A' && script[pc]<='Z' &&
408             script[pc+1]>='A' && script[pc+1]<='Z') ) {
409     gettoken();
410     getopen();
411     if(strcmp(token,"len")==0) {
412       char toto[STRINGL];
413       strcpy(toto,string);
414       getstring();
415       p=strlen(string);
416       strcpy(string,toto);
417     }
418     else if(strcmp(token,"htime")==0) {
419       p=htime();
420     }
421     else if(strcmp(token,"time")==0) {
422       p=time(0);
423     }
424     else if(strcmp(token,"pid")==0) {
425       p=getpid();
426     }
427     else if(strcmp(token,"ppid")==0) {
428       p=getppid();
429     }
430     else if(strcmp(token,"verbose")==0) {
431       p=verbose;
432     }
433     else if(strcmp(token,"isatty")==0) {
434       p=isatty(getvalue());
435     }
436     else if(strcmp(token,"baud")==0) {
437       p=atol(cspeed);
438     }
439     else if(strcmp(token,"access")==0) {
440       char toto[STRINGL];
441       char afile[STRINGL];
442       strcpy(toto,string);
443       getstring();
444       strcpy(afile,string);
445       getcomma();
446       getstring();
447       if(string[0]==0) serror("Missing access mode[s]",5);
448       amode=0;
449       for(a=0;a<strlen(string);a++) {
450         switch(string[a]) {
451           case 'R' :
452           case 'r' : amode|=R_OK; break;
453           case 'W' :
454           case 'w' : amode|=W_OK; break;
455           case 'X' :
456           case 'x' : amode|=X_OK; break;
457           case 'F' :
458           case 'f' : amode|=F_OK; break;
459           default : serror("Access modes are r,w,x, and f",5);
460         }
461       }
462       p=access(afile,amode);
463       strcpy(string,toto);
464     }
465     else if(strcmp(token,"val")==0 || strcmp(token,"atol")==0) {
466       char toto[STRINGL];
467       strcpy(toto,string);
468       getstring();
469       p=atol(string);
470       strcpy(string,toto);
471     }
472     else serror("Unknown Integer function",5);
473     getclose();
474   }
475   if(script[pc]=='%') {
476     pc++;
477     skipspaces();
478     p=resultcode;
479   }
480   while(goone) {
481     if(script[pc]=='+') {
482       pc++;
483       p+=getvalue();
484     }
485     else if(script[pc]=='-') {
486       pc++;
487       p-=getvalue();
488     }
489     else if(script[pc]=='^') {
490       pc++;
491       p^=getvalue();
492     }
493     else if(script[pc]=='&') {
494       pc++;
495       p&=getvalue();
496     }
497     else if(script[pc]=='|') {
498       pc++;
499       p|=getvalue();
500     }
501     else if(script[pc]=='*') {
502       pc++;
503       p*=getvalue();
504     }
505     else if(script[pc]=='/') {
506       pc++;
507       a=getvalue();
508       if(a==0) serror("Division by zero",6);
509       p/=a;
510     }
511     else if((script[pc]>='a' && script[pc]<='z') ||
512             (script[pc]>='A' && script[pc]<='Z') ) {
513       p=intvars[getintindex()];
514     }
515     else if(script[pc]>='0' && script[pc]<='9') {
516       base=10;
517       if(script[pc]=='0') {
518         base=8;
519         pc++;
520         if(script[pc]=='x' || script[pc]=='X') {
521           base=16;
522           pc++;
523         }
524         if(script[pc]=='%') {
525           base=2;
526           pc++;
527         }
528       }
529       while((script[pc]>='0' && script[pc]<='9') ||
530             (script[pc]>='a' && script[pc]<='f') ||
531             (script[pc]>='A' && script[pc]<='F')) {
532         if(script[pc]>='a' && script[pc]<='f') {
533           p=p*base+script[pc++]-'a'+10;
534         }
535         else if(script[pc]>='A' && script[pc]<='F') {
536           p=p*base+script[pc++]-'A'+10;
537         }
538         else {
539           p=p*base+script[pc++]-'0';
540         }
541       }
542     }
543     else {
544       goone=0;
545     }
546   }
547   return(p);
548 }
549
550 void getcomma(void) {
551   skipspaces();
552   if(script[pc++]!=',') serror("Comma expected",5);
553 }
554
555 void gethardstring(void) {
556   int a=0;
557   skipspaces();
558   while(script[pc]!=0 && script[pc]!=' ' && script[pc]!='\t' &&
559         script[pc]!='\n') {
560     string[a++]=script[pc++];
561   }
562   string[a]=0;
563 }
564
565 /* Parse a string from script[pc] */
566 void getstring(void) {
567   FILE *fp;
568   time_t t;
569   unsigned int a,b;
570   int c,p=0;
571   unsigned char ch,match;
572   string[0]=0;
573   skipspaces();
574   if(script[pc]!='"' && script[pc]!='\'' && script[pc]!='$' ) {
575     serror("Expected a string",7);
576   }
577   while(script[pc]!=' ' && script[pc]!='\t' && script[pc]!='\n' && script[pc]!=','  && script[pc]!=')' && script[pc]!='=' && script[pc]!='<' && script[pc]!='>' && script[pc]!='!' ) {
578     if(script[pc]=='+') pc++;
579     skipspaces();
580     if( (script[pc]=='$' && script[pc+1]>='a' && script[pc+1]<='z' &&
581          script[pc+2]>='a' && script[pc+2]<='z') ||
582         (script[pc]=='$' && script[pc+1]>='A' && script[pc+1]<='Z' &&
583          script[pc+2]>='A' && script[pc+2]<='Z') ) {
584       pc++;
585       gettoken();
586       getopen();
587       if(strcmp(token,"time")==0) {
588         t=time(0);
589         strcat(string,ctime(&t));
590         string[strlen(string)-1]=0;
591       }
592       else if(strcmp(token,"rpipe")==0) {
593         char toto[STRINGL];
594         strcpy(toto,string);
595         getstring();
596         if((fp=popen(string,"r"))==NULL) serror("Could not popen!",4);
597         fgets(string,STRINGL-1,fp);
598         string[strlen(string)-1]=0;
599         pclose(fp);
600         strcat(toto,string);
601         strcpy(string,toto);
602       }
603       else if(strcmp(token,"env")==0) {
604         char toto[STRINGL];
605         strcpy(toto,string);
606         getstring();
607         if(getenv(string)) strcat(toto,(char *)getenv(string));
608         strcpy(string,toto);
609       }
610       else if(strcmp(token,"hms")==0) {
611         long sec,min,hour;
612         sec=getvalue();
613         min=sec/60L;
614         sec-=min*60L;
615         hour=min/60L;
616         min-=hour*60L;
617         sprintf(string,"%s%02ld:%02ld:%02ld",string,hour,min,sec);
618       }
619       else if(strcmp(token,"dev")==0) {
620         strcat(string,device);
621       }
622       else if(strcmp(token,"cwd")==0) {
623         getcwd(string,STRINGL);
624       }
625       else if(strcmp(token,"baud")==0) {
626         strcat(string,cspeed);
627       }
628       else if(strcmp(token,"str")==0 || strcmp(token,"ltoa")==0) {
629         sprintf(string,"%s%ld",string,getvalue());
630       }
631       else if(strcmp(token,"hexu")==0) {
632         sprintf(string,"%s%lX",string,getvalue());
633       }
634       else if(strcmp(token,"hex")==0) {
635         sprintf(string,"%s%lx",string,getvalue());
636       }
637       else if(strcmp(token,"oct")==0) {
638         sprintf(string,"%s%lo",string,getvalue());
639       }
640       else if(strcmp(token,"dirname")==0) {
641         char toto[STRINGL];
642         strcpy(toto,string);
643         getstring();
644         b=0;
645         for(a=0;a<strlen(string);a++) {
646           if(string[a]=='/' || string[a]=='\\') b=a;
647         }
648         string[b]=0;
649         strcat(toto,string);
650         strcpy(string,toto);
651       }
652       else if(strcmp(token,"tolower")==0) {
653         char toto[STRINGL];
654         strcpy(toto,string);
655         getstring();
656         for(a=0;a<strlen(string);a++) {
657           if(string[a]>='A' && string[a]<='Z' ) string[a]=string[a]-'A'+'a';
658         }
659         strcat(toto,string);
660         strcpy(string,toto);
661       }
662       else if(strcmp(token,"toupper")==0) {
663         char toto[STRINGL];
664         strcpy(toto,string);
665         getstring();
666         for(a=0;a<strlen(string);a++) {
667           if(string[a]>='a' && string[a]<='z' ) string[a]=string[a]-'a'+'A';
668         }
669         strcat(toto,string);
670         strcpy(string,toto);
671       }
672       else if(strcmp(token,"basename")==0) {
673         char toto[STRINGL];
674         strcpy(toto,string);
675         getstring();
676         b=0;
677         for(a=0;a<strlen(string);a++) {
678           if(string[a]=='/' || string[a]=='\\') b=a+1;
679         }
680         a=strlen(toto);
681         while(string[b]) toto[a++]=string[b++];
682         toto[a]=0;
683         strcpy(string,toto);
684       }
685       else if(strcmp(token,"script")==0) {
686         strcat(string,scriptfile);
687       }
688       else if(strcmp(token,"right")==0) {
689         char toto[STRINGL];
690         strcpy(toto,string);
691         getstring();
692         getcomma();
693         b=getvalue();
694         if(b>strlen(string)) serror("String is shorter than second argument",7);
695         c=strlen(toto);
696         a=strlen(string)-b;
697         while(b!=0 && string[a]!=0) {
698           toto[c++]=string[a++];
699           b--;
700         }
701         toto[c]=0;
702         strcpy(string,toto);
703       }
704       else if(strcmp(token,"left")==0) {
705         char toto[STRINGL];
706         strcpy(toto,string);
707         getstring();
708         getcomma();
709         b=getvalue();
710         if(b>strlen(string)) serror("String is shorter than second argument",7);
711         c=strlen(toto);
712         a=0;
713         while(b!=0 && string[a]!=0) {
714           toto[c++]=string[a++];
715           b--;
716         }
717         toto[c]=0;
718         strcpy(string,toto);
719       }
720       else if(strcmp(token,"mid")==0) {
721         char toto[STRINGL];
722         strcpy(toto,string);
723         getstring();
724         getcomma();
725         a=getvalue();
726         getcomma();
727         b=getvalue();
728         if(a>strlen(string)) serror("String is shorter than second argument",7);
729         c=strlen(toto);
730         while(b!=0 && string[a]!=0) {
731           toto[c++]=string[a++];
732           b--;
733         }
734         toto[c]=0;
735         strcpy(string,toto);
736       }
737       else if(strcmp(token,"sex")==0) {
738         strcat(string,"You're a naughty boy, you!");
739       }
740       else serror("Invalid string funtion",5);
741       getclose();
742     }
743     else if(script[pc]=='$') {
744       strcat(string,stringvars[getstringindex()]);
745     }
746     else if(script[pc]=='"' || script[pc]=='\'') {
747       match=script[pc++];
748       while(script[pc]!=match) {
749         ch=script[pc++];
750         if(ch==0) serror("Umatched quote.",5);
751         if(ch=='\\') {
752           if(script[pc]<='7' && script[pc]>='0' &&
753             script[pc+1]<='7' && script[pc+1]>='0' ) {
754             ch=0;
755             while(script[pc]>='0' && script[pc]<='7') {
756               ch=8*ch+script[pc++]-'0';
757             }
758           }
759           else {
760             switch(script[pc]) {
761               case 'T' :
762               case 't' : ch=9;  break;
763               case 'R' :
764               case 'r' : ch=13; break;
765               case 'N' :
766               case 'n' : ch=10; break;
767               case 'B' :
768               case 'b' : ch=8;  break;
769               case 'F' :
770               case 'f' : ch=12; break;
771               case '"' :
772               case '^' :
773               case '\'' :
774               case '\\' : ch=script[pc]; break;
775               default :  serror("Malformed escaped character",5);
776             }
777             pc++;
778           }
779         }
780         else if(ch=='^') {
781           ch=script[pc];
782           if(ch!='^' && ch!='"' && ch!='\'' && ch!='\\' ) {
783             ch=ch&31; /* Control char */
784           }
785           pc++;
786         }
787         p=strlen(string);
788         string[p++]=ch;
789         string[p]=0;
790       }
791       pc++; /* Space over quote */
792     }
793     else {
794       p=strlen(string);
795       string[p++]=script[pc++];
796       string[p]=0;
797     }
798   }
799 }
800
801 /* Get a value, multiply by a hundred (for time values) */
802 unsigned long getdvalue(void) {
803   float f;
804   gettoken();
805   skipspaces();
806   sscanf(token,"%f",&f);
807   f+=0.00001; /* Rounding errors */
808   return(100.0*f);
809 }
810
811 void dolet(void) {
812   int index;
813   BOOL svar=0;
814   skipspaces();
815   if(script[pc]=='$') {
816     svar=1;
817     index=getstringindex();
818   }
819   else index=getintindex();
820   skipspaces();
821   gettoken();
822   if(strcmp(token,"=")!=0) serror("Bad LET assignment, '=' missing",5);
823   skipspaces();
824   if(svar) {
825     getstring();
826     strcpy(stringvars[index],string);
827   }
828   else {
829     intvars[index]=getvalue();
830   }
831 }
832
833 /* See documentation for doXXX() functions */
834 int dowaitquiet(void) {
835   unsigned long timeout,timequiet,quiet,now;
836   int c,quit;
837   timeout=htime()+getdvalue();
838   quiet=getdvalue();
839   timequiet=htime()+quiet;
840   quit=1;
841   while(quit==1) {
842     now=htime();
843     c=getonebyte();
844     if(c!= -1) timequiet=now+quiet;
845     if(now>=timequiet) quit=0;
846     if(now>=timeout) quit=255;
847   }
848   return(quit);
849 }
850
851 int dowaitfor(void) {
852   char strings[20][80];
853   char buffer[128];
854   unsigned long timeout;
855   unsigned int a;
856   int b,c;
857   b=0;
858   buffer[127]=0;
859   skipspaces();
860   timeout=htime()+getdvalue();
861   while(script[pc]==',' || script[pc]=='$' || script[pc]=='"' ||
862         script[pc]=='\'' ) {
863     if(script[pc]==',') pc++;
864     getstring();
865     skipspaces();
866     strcpy(strings[b],string);
867     if(ignorecase) {
868       for(a=0;a<strlen(strings[b]);a++) {
869         if(strings[b][a]>='A' && strings[b][a]<='Z') {
870           strings[b][a]=strings[b][a]-'A'+'a';
871         }
872       }
873     }
874     b++;
875   }
876   strings[b][0]=0;
877   while(htime()<timeout) {
878     c=getonebyte();
879     //printf("Byte \"%c\" ",c);
880     if(c!= -1) {
881       if(ignorecase) {
882         if(c>='A' && c<='Z') c=c-'A'+'a';
883       }
884       for(a=0;a<127;a++) buffer[a]=buffer[a+1]; //shuffle down
885       buffer[126]=c;
886       b=0;
887       while(strings[b][0]) {
888         c=strlen(strings[b]);
889         if (strcmp(strings[b],&buffer[127-c]) == 0){
890           return(b);
891         }
892         b++;
893       }
894     }
895   }
896   return(-1);
897 }
898
899 /* Parse script for "on" or "off" wich are tokens, not strings */
900 BOOL getonoroff(void) {
901   int a,b;
902   b=pc;
903   gettoken();
904   if(strcmp(token,"on")==0) return(1);
905   if(strcmp(token,"off")==0) return(0);
906   pc=b;
907   a=getvalue();
908   if(a!=0 && a!=1) serror("Bad value (should be on or off, 1 or 0.)",5);
909   return(a);
910 }
911
912 void setcom(void) {
913   stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | CLOCAL | PARENB);
914   stbuf.c_cflag |= (speed | bits | CREAD | clocal | parity | stopbits );
915   if (ioctl(comfd, TCSETA, &stbuf) < 0) {
916     serror("Can't ioctl set device",1);
917   }
918 }
919
920 void doset(void) {
921   struct termio console;
922   int a,b;
923   gettoken();
924   if(strcmp(token,"echo")==0) {
925     a=0;
926     if(getonoroff()) a=ECHO|ECHOE;
927     if(ioctl(0, TCGETA, &console)<0) {
928       serror("Can't ioctl FD zero!\n",2);
929     }
930     console.c_lflag &= ~(ECHO | ECHOE);
931     console.c_lflag |= a;
932     ioctl(0, TCSETA, &console);
933   }
934   else if(strcmp(token,"senddelay")==0) {
935     senddelay=10000L*getdvalue();
936   }
937   else if(strcmp(token,"clocal")==0) {
938     clocal=0;
939     if(getonoroff()) clocal=CLOCAL;
940     setcom();
941   }
942   else if(strcmp(token,"umask")==0) {
943     umask(getvalue()&0777);
944   }
945   else if(strcmp(token,"verbose")==0) {
946     verbose=getonoroff();
947   }
948   else if(strcmp(token,"comecho")==0) {
949     comecho=getonoroff();
950   }
951   else if(strcmp(token,"ignorecase")==0) {
952     ignorecase=getonoroff();
953   }
954   else if(strcmp(token,"com")==0) {
955     skipspaces();
956     if(script[pc]=='$' || script[pc]=='\'' || script[pc]=='"') {
957       getstring();
958       strcpy(token,string);
959     }
960     else gettoken();
961     a=0;
962     b=0;
963     while(token[b]>='0' && token[b]<='9') {
964       a=10*a+token[b++]-'0';
965     }
966     if(token[b]) {
967       switch(token[b]) {
968         case 'n': parity=0; break;
969         case 'e': parity=PARENB; break;
970         case 'o': parity=PARENB|PARODD; break;
971         default : serror("Parity can only ben E, N, or O",5);
972       }
973       b++;
974       if(token[b]) {
975         switch(token[b]) {
976           case '5' : bits=CS5; break;
977           case '6' : bits=CS6; break;
978           case '7' : bits=CS7; break;
979           case '8' : bits=CS8; break;
980           default : serror("Bits can only be 5, 6, 7, or 8",5);
981         }
982         b++;
983         if(token[b]) {
984           switch(token[b]) {
985             case '1': stopbits=0; break;
986             case '2': stopbits=CSTOPB; break;
987             default : serror("Stop bits can only be 1 or 2",5);
988           }
989         }
990       }
991     }
992     sprintf(cspeed,"%d",a);
993     switch(a) {
994       case 0: speed = B0;break;
995       case 50: speed = B50;break;
996       case 75: speed = B75;break;
997       case 110: speed = B110;break;
998       case 150: speed = B150;break;
999       case 300: speed = B300;break;
1000       case 600: speed = B600;break;
1001       case 1200: speed = B1200;break;
1002       case 2400: speed = B2400;break;
1003       case 4800: speed = B4800;break;
1004       case 9600: speed = B9600;break;
1005       case 19200: speed = B19200;break;
1006       case 38400: speed = B38400;break;
1007       case 57600: speed = B57600;break;
1008       case 115200: {
1009                     if(high_speed == 0) speed = B115200;
1010                     else speed = B57600;
1011                     break;
1012                   }
1013       case 460800: speed = B460800; break;
1014       default: serror("Invalid baudrate",1);
1015     }
1016     setcom();
1017   }
1018 }
1019
1020 void dogoto(void) {
1021   int a,originalpos;
1022   originalpos=pc;
1023   gettoken();
1024   for(a=0;a<labels;a++) {
1025     if(strcmp(token,label[a])==0) break;
1026   }
1027   if(a>=labels) {
1028     pc=originalpos;
1029     sprintf(msg,"Label \"%s\" not found",token);
1030     serror(msg,5);
1031   }
1032   else {
1033     pc=labelpc[a];
1034   }
1035 }
1036
1037 void dogosub(void) {
1038   int a;
1039   if(preturn==MAXGOSUBS) serror("Reached maximum GOSUB depth",3);
1040   a=pc;
1041   gettoken();
1042   returns[preturn++]=pc;
1043   pc=a;
1044   dogoto();
1045 }
1046
1047 /* Gets arguments and returns 0 for a string, 1 for an int. Used with if */
1048 BOOL getonearg(void) {
1049   if(script[pc]=='"' || script[pc]=='\'' || script[pc]=='$' ) {
1050     getstring();
1051     return(0);
1052   }
1053   else {
1054     number=getvalue();
1055     return(1);
1056   }
1057 }
1058
1059 void doif(void) {
1060   char stringarg[STRINGL];
1061   char tokencopy[MAXTOKEN];
1062   int intarg;
1063   skipspaces();
1064   ifres=0;
1065   if(getonearg()) {
1066     intarg=number;
1067     gettoken();
1068     skipspaces();
1069     if(getonearg()!=1) serror("Comparison mis-match",7);
1070     if(strcmp(token,"<")==0) {
1071       if(intarg<number) ifres=1;
1072     }
1073     if(strcmp(token,"<=")==0) {
1074       if(intarg<=number) ifres=1;
1075     }
1076     else if(strcmp(token,"=")==0) {
1077       if(intarg==number) ifres=1;
1078     }
1079     else if(strcmp(token,">")==0) {
1080       if(intarg>number) ifres=1;
1081     }
1082     else if(strcmp(token,">=")==0) {
1083       if(intarg>=number) ifres=1;
1084     }
1085     else if(strcmp(token,"<>")==0) {
1086       if(intarg!=number) ifres=1;
1087     }
1088     else if(strcmp(token,"!=")==0 || strcmp(token,"<>")==0) {
1089       if(intarg!=number) ifres=1;
1090     }
1091   }
1092   else {
1093     strcpy(stringarg,string);
1094     gettoken();
1095     strcpy(tokencopy,token);
1096     skipspaces();
1097     if(getonearg()!=0) serror("Comparison mis-match",7);
1098     if(strcmp(tokencopy,"<")==0) {
1099       if(strcmp(stringarg,string)<0) ifres=1;
1100     }
1101     if(strcmp(tokencopy,"<=")==0) {
1102       if(strcmp(stringarg,string)<=0) ifres=1;
1103     }
1104     else if(strcmp(tokencopy,"=")==0) {
1105       if(strcmp(stringarg,string)==0) ifres=1;
1106     }
1107     else if(strcmp(tokencopy,">")==0) {
1108       if(strcmp(stringarg,string)>0) ifres=1;
1109     }
1110     else if(strcmp(tokencopy,">=")==0) {
1111       if(strcmp(stringarg,string)>=0) ifres=1;
1112     }
1113     else if(strcmp(tokencopy,"!=")==0 || strcmp(tokencopy,"<>")==0) {
1114       if(strcmp(stringarg,string)!=0) ifres=1;
1115     }
1116   }
1117   if(!ifres) skipline();
1118 }
1119
1120 int getindex(void) {
1121   int index;
1122   index=script[pc++];
1123   if(index>='A' && index<='Z') index=index-'A'+'a';
1124   if(index>'z' || index<'a') serror("Malformed variable name",7);
1125   index=index-'a';
1126   if(script[pc]>='0' && script[pc]<='9') {
1127     index=index+(1+script[pc++]-'0')*26;
1128   }
1129   return(index);
1130 }
1131
1132 /* Parse script to find integer variable index */
1133 int getintindex(void) {
1134   skipspaces();
1135   if(script[pc]=='$') serror("Integer variable expected",7);
1136   return(getindex());
1137 }
1138
1139 /* Parse script to find string variable index and allocate memory for storage
1140    as needed. */
1141 int getstringindex(void) {
1142   int index;
1143   skipspaces();
1144   if(script[pc++]!='$') serror("String variable expected",7);
1145   index=getindex();
1146   if(stringvars[index]==NullString) {
1147     stringvars[index]=(char *)malloc(STRINGL);
1148     if(stringvars[index]==NULL) serror("Could not malloc",3);
1149     stringvars[index][0]=0;
1150   }
1151   return(index);
1152 }
1153
1154 void doget(void) {
1155   char terminators[STRINGL];
1156   unsigned int a;
1157   int b,c,index;
1158   int goahead=1;
1159   unsigned long timeout;
1160   timeout=htime()+getdvalue();
1161   getstring();
1162   strcpy(terminators,string);
1163   index=getstringindex();
1164   string[0]=0;
1165   b=0;
1166   resultcode=0;
1167   while(goahead && htime()<timeout) {
1168     c=getonebyte();
1169     if(c!= -1) {
1170       for(a=0;a<strlen(terminators);a++) {
1171         if(c==terminators[a]) goahead=0;
1172       }
1173       if(goahead==0 && b==0) goahead=1; /* Ignore terminators if nothing yet */
1174       else if(goahead) {
1175         string[b++]=c;
1176         string[b]=0;
1177       }
1178     }
1179   }
1180   if(goahead) resultcode= -1;
1181   strcpy(stringvars[index],string);
1182 }
1183
1184 void doprint(int channel) {
1185   skipspaces();
1186   msg[0]=0;
1187   while(script[pc]!=' ' && script[pc]!='\t' && script[pc]!='\n') {
1188     if(script[pc]==',') pc++;
1189     else {
1190       if(script[pc]=='"' || script[pc]=='\'' || script[pc]=='$' ) {
1191         getstring();
1192         strcat(msg,string);
1193       }
1194       else {
1195         sprintf(string,"%ld",getvalue());
1196         strcat(msg,string);
1197       }
1198     }
1199   }
1200   switch(channel) {
1201     case 1: printf("%s",msg); fflush(stdout); break;
1202     case 2: fputs(msg,stderr); break;
1203     case 3:
1204       if(msg[strlen(msg)-1]=='\n') msg[strlen(msg)-1]=0;
1205       vmsg(msg);
1206       break;
1207     case 4:
1208       if(filep==NULL) serror("File not opened",4);
1209       fputs(msg,filep);
1210       break;
1211   }
1212 }
1213
1214 void doclose(void) {
1215   gettoken();
1216   if(strcmp(token,"hardcom")==0) {
1217     if(comfd== -1) serror("Com device not open",1);
1218     vmsg("Closing device");
1219     if (ioctl(comfd, TCSETA, &svbuf) < 0) {
1220       sprintf(msg,"Can't ioctl set device %s.\n",device);
1221       serror(msg,1);
1222     }
1223     close(comfd);
1224     comfd= -1;
1225   }
1226   else if(strcmp(token,"com")==0) {
1227     if(comfd== -1) serror("Com device not open",1);
1228     vmsg("Closing com fd");
1229     close(comfd);
1230     comfd= -1;
1231   }
1232   else if(strcmp(token,"file")==0) {
1233     if(filep==NULL) serror("Log file not open",4);
1234     fclose(filep);
1235     filep=NULL;
1236   }
1237 }
1238
1239 void opengt(void) {
1240   if(strcmp(device,"-")!=0) {
1241     if ((comfd = open(device, O_RDWR|O_EXCL|O_NONBLOCK|O_NOCTTY)) <0) { //O_NONBLOCK|O_NOCTTY)) <0) {//
1242       sprintf(msg,"Can't open GlobeTrotter %s.\n",device);
1243       printf(msg);
1244       ext(1);
1245     }
1246   }
1247   else comfd=0;
1248   if (ioctl (comfd, TCGETA, &svbuf) < 0) {
1249     sprintf(msg,"Can't control %s, please try again.\n",device);
1250     serror(msg,1);
1251   }
1252   ioctl(comfd, TCGETA, &stbuf);
1253   speed=stbuf.c_cflag & CBAUD;
1254   if (high_speed == 0)  strcpy(cspeed,"115200");
1255   else strcpy(cspeed,"57600");
1256   bits=stbuf.c_cflag & CSIZE;
1257   clocal=stbuf.c_cflag & CLOCAL;
1258   stopbits=stbuf.c_cflag & CSTOPB;
1259   parity=stbuf.c_cflag & (PARENB | PARODD);
1260   stbuf.c_iflag &= ~(IGNCR | ICRNL | IUCLC | INPCK | IXON | IXANY | IGNPAR );
1261   stbuf.c_oflag &= ~(OPOST | OLCUC | OCRNL | ONLCR | ONLRET);
1262   stbuf.c_lflag &= ~(ICANON | XCASE | ECHO | ECHOE | ECHONL);
1263   stbuf.c_lflag &= ~(ECHO | ECHOE);
1264   stbuf.c_cc[VMIN] = 1;
1265   stbuf.c_cc[VTIME] = 0;
1266   stbuf.c_cc[VEOF] = 1;
1267   setcom();
1268   dormir(200000); /* Wait a bit (DTR raise) */
1269   sprintf(msg,"Opened %s as FD %d",device,comfd);
1270   vmsg(msg);
1271 }
1272   
1273 void opendevice(void) {
1274   if(strcmp(device,"-")!=0) {
1275     if ((comfd = open(device, O_RDWR|O_EXCL|O_NONBLOCK|O_NOCTTY)) <0) { //O_NONBLOCK|O_NOCTTY)) <0) {//
1276       sprintf(msg,"Can't open device %s.\n",device);
1277       printf(msg);
1278       ext(1);
1279     }
1280   }
1281   else comfd=0;
1282   if (ioctl (comfd, TCGETA, &svbuf) < 0) {
1283     sprintf(msg,"Can't ioctl get device %s.\n",device);
1284     serror(msg,1);
1285   }
1286   ioctl(comfd, TCGETA, &stbuf);
1287   speed=stbuf.c_cflag & CBAUD;
1288   switch(speed) {
1289     case B0: strcpy(cspeed,"0");break;
1290     case B50: strcpy(cspeed,"50");break;
1291     case B75: strcpy(cspeed,"75");break;
1292     case B110: strcpy(cspeed,"110");break;
1293     case B300: strcpy(cspeed,"300");break;
1294     case B600: strcpy(cspeed,"600");break;
1295     case B1200: strcpy(cspeed,"1200");break;
1296     case B2400: strcpy(cspeed,"2400");break;
1297     case B4800: strcpy(cspeed,"4800");break;
1298     case B9600: strcpy(cspeed,"9600");break;
1299     case B19200: strcpy(cspeed,"19200");break;
1300     case B38400: strcpy(cspeed,"38400");break;
1301     case B115200: 
1302                 {
1303                   if (high_speed == 0) strcpy(cspeed,"115200");
1304                   else strcpy(cspeed,"57600");
1305                   break;
1306                 }
1307     case B460800: strcpy(cspeed, "460800");break;
1308   }
1309   bits=stbuf.c_cflag & CSIZE;
1310   clocal=stbuf.c_cflag & CLOCAL;
1311   stopbits=stbuf.c_cflag & CSTOPB;
1312   parity=stbuf.c_cflag & (PARENB | PARODD);
1313   stbuf.c_iflag &= ~(IGNCR | ICRNL | IUCLC | INPCK | IXON | IXANY | IGNPAR );
1314   stbuf.c_oflag &= ~(OPOST | OLCUC | OCRNL | ONLCR | ONLRET);
1315   stbuf.c_lflag &= ~(ICANON | XCASE | ECHO | ECHOE | ECHONL);
1316   stbuf.c_lflag &= ~(ECHO | ECHOE);
1317   stbuf.c_cc[VMIN] = 1;
1318   stbuf.c_cc[VTIME] = 0;
1319   stbuf.c_cc[VEOF] = 1;
1320   setcom();
1321   dormir(200000); /* Wait a bit (DTR raise) */
1322   sprintf(msg,"Opened %s as FD %d",device,comfd);
1323   vmsg(msg);
1324 }
1325
1326 void doopen(void) {
1327   gettoken();
1328   if(strcmp(token,"com")==0) {
1329     skipspaces();
1330     if(script[pc]=='$' || script[pc]=='\'' || script[pc]=='"') {
1331       getstring();
1332     }
1333     else gethardstring();
1334     strcpy(device,string);
1335     opendevice();
1336   }
1337   else if (strcmp(token,"file")==0) {
1338     if(filep!=NULL) serror("File already open",4);
1339     getstring();
1340     if((filep=fopen(string,"a"))==NULL) serror("Could not open file",4);
1341   }
1342   else serror("OPEN only takes com or file argument",5);
1343 }
1344
1345 int doscript(void) {
1346   int a,b;
1347   int exitcode=0;
1348   char line[STRINGL];
1349   pc=0;
1350   while(script[pc]) {
1351     if(script[pc]=='\n') pc++;
1352     lastpc=pc;
1353     skipspaces();
1354     if(verbose) printwhere();
1355     if(gettoken()) serror("Could not gettoken()",5);
1356     if(strcmp(token,"rem")==0) {
1357       skipline();
1358     }
1359     else if (strcmp(token,"label")==0) {
1360       skiptoken(); /* Get rid of keyword */
1361     }
1362     else if(strcmp(token,"open")==0) {
1363       doopen();
1364     }
1365     else if(strcmp(token,"opengt")==0) {
1366       opengt();
1367     }
1368     else if(strcmp(token,"close")==0) {
1369       doclose();
1370     }
1371     else if(strcmp(token,"exec")==0) {
1372       getstring();
1373       strcpy(msg,"exec ");
1374       strcat(msg,string); /* Let sh do all the command line work! */
1375       execl("/bin/sh","sh","-c",msg,(char *)0);
1376       serror("Could not execl /bin/sh!",8);
1377     }
1378     else if(strcmp(token,"exit")==0) {
1379       ext(getvalue());
1380     }
1381     else if(strcmp(token,"testkey")==0) {
1382       dotestkey();
1383     }
1384     else if(strcmp(token,"kill")==0) {
1385       a=getvalue();
1386       resultcode=kill(getvalue(),a);
1387     }
1388     else if(strcmp(token,"fork")==0) {
1389       resultcode=fork();
1390     }
1391     else if(strcmp(token,"hset")==0) {
1392       hset=0;
1393       hstart=time(0);
1394       hset=htime()-getvalue();
1395     }
1396     else if(strcmp(token,"cd")==0) {
1397       getstring();
1398       resultcode=chdir(string);
1399     }
1400     else if(strcmp(token,"putenv")==0) {
1401       getstring();
1402       strcpy(line,string);
1403       resultcode=putenv(line); /* putenv can't read from global string[] */
1404     }
1405     else if(strcmp(token,"wait")==0) {
1406       resultcode=wait(0);
1407     }
1408     else if(strcmp(token,"system")==0) {
1409       getstring();
1410       system(string);
1411     }
1412     else if(strcmp(token,"input")==0) {
1413       FILE *infd = fdopen(0,"r");
1414       fgets(stringvars[getstringindex()],1024,infd);
1415       //fclose(infd);
1416     }
1417     else if(strcmp(token,"get")==0) {
1418       doget();
1419     }
1420     else if(strcmp(token,"print")==0) {
1421       doprint(1);
1422     }
1423     else if(strcmp(token,"eprint")==0) {
1424       doprint(2);
1425     }
1426     else if(strcmp(token,"lprint")==0) {
1427       doprint(3);
1428     }
1429     else if(strcmp(token,"fprint")==0) {
1430       doprint(4);
1431     }
1432     else if(strcmp(token,"if")==0) {
1433       doif();
1434     }
1435     else if(strcmp(token,"else")==0) {
1436       if(ifres) skipline();
1437     }
1438     else if(strcmp(token,"gosub")==0) {
1439       dogosub();
1440     }
1441     else if(strcmp(token,"return")==0) {
1442       if(preturn==0) serror("RETURN without gosub",5);
1443       pc=returns[--preturn];
1444     }
1445     else if(strcmp(token,"goto")==0) {
1446       dogoto();
1447     }
1448     else if(strcmp(token,"waitfor")==0) {
1449       resultcode=dowaitfor();
1450     }
1451     else if(strcmp(token,"waitquiet")==0) {
1452       resultcode=dowaitquiet();
1453     }
1454     else if(strcmp(token,"set")==0) {
1455       doset();
1456     }
1457     else if(strcmp(token,"dec")==0) {
1458       intvars[getintindex()]--;
1459     }
1460     else if(strcmp(token,"inc")==0) {
1461       intvars[getintindex()]++;
1462     }
1463     else if(strcmp(token,"let")==0) {
1464       dolet();
1465     }
1466     else if(strcmp(token,"dump")==0) {
1467       dodump();
1468     }
1469     else if(strcmp(token,"abort")==0) {
1470       vmsg("Aborting");
1471       abort();
1472     }
1473     else if(strcmp(token,"send")==0) {
1474       getstring();
1475       writecom(string);
1476     }
1477     else if(strcmp(token,"flash")==0) {
1478       b=speed;
1479       speed=0;
1480       setcom();
1481       a=getdvalue();
1482       dormir(10000L*a);
1483       speed=b;
1484       setcom();
1485     }
1486     else if(strcmp(token,"sleep")==0) {
1487       a=getdvalue();
1488       if(a<10000) dormir(10000L*a);
1489       else sleep(a/100); /* I guess it's the same.  Oh well, past 100 secs,
1490                             use sleep instead.  */
1491     }
1492     else {
1493       /* Humour is the spice of life. */
1494       switch(time(0)&7) {
1495         case 0 : serror("That's human mumbo-jumbo to me",5); break;
1496         case 1 : serror("Lovely but incomprehensible",5); break;
1497         case 2 : serror("What's that, governor?",5); break;
1498         case 3 : serror("Very funny.  I don't get it",5); break;
1499         case 4 : serror("Huh?",5); break;
1500         case 5 : serror("gcom doesn't speak spanish",5); break;
1501         case 6 : serror("Mais, qu'est-ce que vous dites?",5); break;
1502         default: serror("%E-6837-% : Corrupted human data detected",5); break;
1503       }
1504     }
1505     skipspaces();
1506     while(script[pc]=='\n') pc++;
1507   }
1508   return(exitcode);
1509 }
1510
1511 int main(int argc,char **argv) {
1512   unsigned int a;
1513   int aa,b,i,skip_default;
1514   unsigned char ch;
1515   unsigned char terminator='\n';
1516   char line[STRINGL];
1517   
1518   strcpy(device,GTDEVICE);
1519   FILE *fp;
1520   hstart=time(0);
1521   hset=htime();
1522   preturn=0;
1523   skip_default=0;
1524   filep=NULL;
1525   scriptspace=4096;
1526   ioctl(1, TCGETA, &cons);
1527   if((script=( char *)malloc(scriptspace))==NULL) {
1528     serror("Could not malloc()",3);
1529   }
1530   for(a=0;a<NVARS;a++) {
1531     intvars[a]=0;
1532     stringvars[a]=NullString;
1533   }
1534   strcpy(cspeed,"0");
1535   scriptfile[0]=0;
1536   b=0; a=0;
1537   for(a=0;a<strlen(argv[0]);a++) {
1538     if(argv[0][a]=='/') b=a+1;
1539   }
1540   while((aa=getopt(argc,argv,"xhevd:t:sb:"))!= -1) {
1541     switch(aa) {
1542       case 0:
1543         ext(0);
1544         break;
1545       case 't':
1546         terminator=optarg[0];
1547         sprintf(msg,"Alternate line terminator set to \"%c\"",terminator);
1548         vmsg(msg);
1549         break;
1550       case 'd':
1551         strcpy(device,optarg);
1552         //opendevice();
1553         break;
1554       case 'e':
1555         comecho=1;
1556         vmsg("Communication echo turned on");
1557         break;
1558       case 'v':
1559         verbose=1;
1560         vmsg("Verbose output enabled");
1561         break;
1562       case 's':
1563         skip_default=1;
1564         break;
1565       case 'h':
1566         printf("gcom version 0.3 Copyright Paul Hardwick (c) 2005 \n");
1567         printf("\nType 'gcom help' for more information\n");
1568         ext(1);
1569         break;
1570       case 'x':
1571         printf("High speed overide (115200 is now 57600).\n");
1572         high_speed =1;
1573         break;
1574       default:
1575         ext(1);
1576     }
1577   }
1578   if(optind<argc) {
1579     strcpy(scriptfile,argv[optind++]);
1580     sprintf(msg,"Script file: %s",scriptfile);
1581     vmsg(msg);
1582   }
1583
1584   char * code;
1585   code = get_code(scriptfile);
1586   if (code != NULL){
1587     scriptspace=strlen(code)+2;
1588     if((script=( char *)realloc(script,scriptspace))==0) {
1589        serror("Could not malloc()",3);
1590        }
1591        strcpy(script,code);
1592       for(aa=0;aa<scriptspace;aa++) {
1593          if(script[aa]==terminator) script[aa]='\n';
1594       }
1595       //scriptfile[0] = '\0';
1596     }
1597   else if (scriptfile[0]) {
1598         code = get_code("default");
1599         if (code != NULL && !skip_default){
1600                 scriptspace=strlen(code)+2;
1601                 if((script=( char *)realloc(script,scriptspace))==0) {
1602                         serror("Could not malloc()",3);
1603                 }
1604                 strcpy(script,code);
1605                 for(aa=0;aa<scriptspace;aa++) {
1606                         if(script[aa]==terminator) script[aa]='\n';
1607                 }
1608       //scriptfile[0] = '\0';
1609     }  
1610     if((fp=fopen(scriptfile,"r"))==NULL) {
1611       sprintf(msg,"Could not open scriptfile \"%s\".\n",scriptfile);
1612       serror(msg,1);
1613     }
1614     i=strlen(script);
1615     if(i) {
1616       script[i++]='\n'; script[i]=0;
1617     }
1618     while((fgets(line,STRINGL-1,fp))!=NULL) {
1619       b=strlen(line);
1620       if((scriptspace-i)<STRINGL) {
1621         scriptspace+=STRINGL+STRINGL;
1622         if((script=(char *)realloc(script,scriptspace))==NULL) {
1623           serror("Could not realloc()",3);
1624         }
1625       }
1626       for(aa=0;aa<b;aa++) {
1627         script[i]=line[aa];
1628         if(script[i]==terminator) script[i]='\n';
1629         i++;
1630       }
1631     }
1632     script[i]=0;
1633     fclose(fp);
1634   }
1635
1636   if(script[0]) {
1637     i=strlen(script)-1;
1638     while((script[i]=='\n' || script[i]==' ' || script[i]=='\t') && i!=0) i--;
1639     script[++i]='\n';
1640     script[++i]=0;
1641   }
1642   i=strlen(script); /* Script is one huge string */
1643   /* Indexing labels */
1644   label=(char **)malloc(sizeof(char *)*MAXLABELS);
1645   labelpc=(int *)malloc(sizeof(int *)*MAXLABELS);
1646   if(label==NULL || labelpc==NULL) {
1647     serror("Can't malloc",3);
1648   }
1649   labels=0;
1650   pc=0;
1651   while(script[pc]) {
1652     lastpc=pc;
1653     gettoken();
1654     if(strcmp(token,"label")==0) {
1655       gettoken();
1656       for(aa=0;aa<labels;aa++) {
1657         if(strcmp(token,label[aa])==0) {
1658           pc=lastpc;
1659           serror("Duplicate label",5);
1660         }
1661       }
1662       if(labels==MAXLABELS) serror("Maximum number of labels reached",3);
1663       labelpc[labels]=lastpc;
1664       label[labels]=(char *)malloc(strlen(token)+1);
1665       if(label[labels]==NULL) serror("Can't malloc one label",3);
1666       strcpy(label[labels],token);
1667       labels++;
1668     }
1669     skipline();
1670   }
1671   //printf(script);
1672   if(verbose) {
1673     sprintf(msg,"argc:%d",argc);
1674     vmsg(msg);
1675     for(aa=0;aa<argc;aa++) {
1676       sprintf(msg,"argv[%d]=%s",aa,argv[aa]);
1677       vmsg(msg);
1678     }
1679     vmsg(" ---Script---");
1680     aa=0; b=0; ch='\n';
1681     while(aa<i) {
1682       if(ch=='\n' && script[aa]!=0) {
1683         fprintf(stderr,"%4d@%04d ",++b,aa);
1684       }
1685       ch=script[aa++];
1686       fputc(ch,stderr);
1687     }
1688     vmsg(" ---End of script---");
1689   }
1690
1691   if(script[0]==0) {
1692     fprintf(stderr,"No script!\n");
1693     ext(1);
1694   }
1695
1696   a=doscript();
1697   dormir(200000);
1698   if(comfd!= -1) close(comfd);
1699   sprintf(msg,"Exit with code %d.\n",a);
1700   vmsg(msg);
1701   ext(a);
1702 }