2 * gcom version 0.3 - 3G/GPRS datacard management utility
4 * Copyright (C) 2003 Paul Hardwick <paul@peck.org>
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.
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.
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
20 * See gcom.doc for more configuration and usage information.
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 ****************************************************************************/
40 #include <sys/types.h>
41 #include <sys/ioctl.h>
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"
53 #define BOOL unsigned char
54 #define NVARS 286 /* a-z, a0-z9 == 26*11 */
57 extern int optind, opterr;
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 */
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];
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 */
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";
95 unsigned long htime(void);
96 void dormir(unsigned long microsecs);
99 void vmsg(char *text);
101 void printwhere(void);
102 void writecom(char *text);
103 int getonebyte(void);
105 void serror(char *text, int exitcode);
106 void skipspaces(void);
110 void skiptoken(void);
113 void gethardstring(void);
114 void getstring(void);
115 unsigned long getdvalue(void);
117 int dowaitquiet(void);
119 BOOL getonoroff(void);
124 unsigned char getonearg(void);
127 int getintindex(void);
128 int getstringindex(void);
130 void doprint(int channel);
132 void opendevice(void);
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);
143 /* I use select() 'cause CX/UX 6.2 doesn't have usleep().
144 On Linux, usleep() uses select() anyway.
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);
153 /* Tests for ENTER key */
154 void dotestkey(void) {
156 struct timeval timeout;
158 timeout.tv_usec=10000L;
160 FD_SET(0,&fds); /* Prepare to select() from stdin */
161 resultcode=select(1,&fds,0,0,&timeout);
162 if(resultcode) getchar();
165 /* Exit after resetting terminal settings */
167 ioctl(1, TCSETA, &cons);
171 /* Log message if verbose is on */
172 void vmsg(char *text) {
177 fprintf(stderr,"\n");
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],
188 /* Skip to next statement */
189 void skipline(void) {
190 while(script[pc]!='\n' && script[pc]!=0) pc++;
194 void printwhere(void) {
196 sprintf(msg,"@%04d ",pc);
202 for(;a<b;a++) msg[c++]=script[a];
207 /* Write a null-terminated string to communication device */
208 void writecom(char *text) {
212 for(a=0;a<strlen(text);a++) {
214 res=write(comfd,&ch,1);
215 if(senddelay) dormir(senddelay);
217 serror("Could not write to COM device",1);
222 /* Gets a single byte from comm. device. Return -1 if none avail. */
223 int getonebyte(void) {
228 struct timeval timeout;
230 timeout.tv_usec=10000;
232 FD_SET(comfd, &rfds);
233 res=select(comfd+1,&rfds,NULL,NULL,&timeout);
235 res=read(comfd,&ch,1);
238 if(ch=='\n') lastcharnl=1;
240 if(ch!='\r') lastcharnl=0;
242 /*fputc(ch,stderr);*/
248 return(-1); /* Nada. */
258 sprintf(lmsg,"-- Integer variables --"); vmsg(lmsg);
261 if(intvars[b*26+a]) {
262 sprintf(lmsg," = %ld",intvars[b*26+a]);
265 if(b) lmsg[2]='0'+b-1;
270 sprintf(lmsg,"-- String variables --"); vmsg(lmsg);
273 if(stringvars[b*26+a]!=NullString) {
274 sprintf(lmsg,"$ = \"%s\"",stringvars[b*26+a]);
277 if(b) lmsg[2]='0'+b-1;
285 /* Report script errors and quit */
286 void serror(char *text, int exitcode) {
291 vmsg("-- Error Report --");
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';
308 if(script[a++]=='\n') {
312 sprintf(lmsg,"Error @%d, line %d, %s. (%d)\n",pc,line,text,exitcode);
317 void skipspaces(void) {
318 while(script[pc]==' ' || script[pc]=='\t' ) pc++;
325 if(script[pc++]!='(') {
327 serror("Function requires open parenthesis",5);
331 void getclose(void) {
335 if(script[pc++]!=')') {
337 serror("Function requires close parenthesis",5);
341 void skiptoken(void) {
343 while(script[pc]!=' ' && script[pc]!='\t' && script[pc]!='\n' ) pc++;
347 /* Parse script[pc] to get next statement. Resolve comments and labels... */
351 if(script[pc]=='=' || script[pc]=='<' || script[pc]=='>' || script[pc]=='!') {
353 while(script[pc]=='=' || script[pc]=='<' || script[pc]=='>' || script[pc]=='!') {
354 token[tokenp++]=script[pc++];
359 if(script[pc]=='#') {
364 if(script[pc]=='/' && script[pc+1]=='/') {
369 if(script[pc]==':') {
370 strcpy(token,"label");
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';
380 if(tokenp++==MAXTOKEN-1) serror("Token too long",5);
383 if(strcmp(token,"then")==0) return(gettoken()); /* Ignore then for if */
387 /* shitfaced recursive value parser. must write better one */
388 long getvalue(void) {
394 if(script[pc]=='(') {
399 else if(script[pc]==')') {
402 else if(script[pc]=='"' || script[pc]=='\'' || script[pc]=='$' ) {
403 serror("Did not expect a string",7);
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') ) {
411 if(strcmp(token,"len")==0) {
418 else if(strcmp(token,"htime")==0) {
421 else if(strcmp(token,"time")==0) {
424 else if(strcmp(token,"pid")==0) {
427 else if(strcmp(token,"ppid")==0) {
430 else if(strcmp(token,"verbose")==0) {
433 else if(strcmp(token,"isatty")==0) {
434 p=isatty(getvalue());
436 else if(strcmp(token,"baud")==0) {
439 else if(strcmp(token,"access")==0) {
444 strcpy(afile,string);
447 if(string[0]==0) serror("Missing access mode[s]",5);
449 for(a=0;a<strlen(string);a++) {
452 case 'r' : amode|=R_OK; break;
454 case 'w' : amode|=W_OK; break;
456 case 'x' : amode|=X_OK; break;
458 case 'f' : amode|=F_OK; break;
459 default : serror("Access modes are r,w,x, and f",5);
462 p=access(afile,amode);
465 else if(strcmp(token,"val")==0 || strcmp(token,"atol")==0) {
472 else serror("Unknown Integer function",5);
475 if(script[pc]=='%') {
481 if(script[pc]=='+') {
485 else if(script[pc]=='-') {
489 else if(script[pc]=='^') {
493 else if(script[pc]=='&') {
497 else if(script[pc]=='|') {
501 else if(script[pc]=='*') {
505 else if(script[pc]=='/') {
508 if(a==0) serror("Division by zero",6);
511 else if((script[pc]>='a' && script[pc]<='z') ||
512 (script[pc]>='A' && script[pc]<='Z') ) {
513 p=intvars[getintindex()];
515 else if(script[pc]>='0' && script[pc]<='9') {
517 if(script[pc]=='0') {
520 if(script[pc]=='x' || script[pc]=='X') {
524 if(script[pc]=='%') {
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;
535 else if(script[pc]>='A' && script[pc]<='F') {
536 p=p*base+script[pc++]-'A'+10;
539 p=p*base+script[pc++]-'0';
550 void getcomma(void) {
552 if(script[pc++]!=',') serror("Comma expected",5);
555 void gethardstring(void) {
558 while(script[pc]!=0 && script[pc]!=' ' && script[pc]!='\t' &&
560 string[a++]=script[pc++];
565 /* Parse a string from script[pc] */
566 void getstring(void) {
571 unsigned char ch,match;
574 if(script[pc]!='"' && script[pc]!='\'' && script[pc]!='$' ) {
575 serror("Expected a string",7);
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++;
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') ) {
587 if(strcmp(token,"time")==0) {
589 strcat(string,ctime(&t));
590 string[strlen(string)-1]=0;
592 else if(strcmp(token,"rpipe")==0) {
596 if((fp=popen(string,"r"))==NULL) serror("Could not popen!",4);
597 fgets(string,STRINGL-1,fp);
598 string[strlen(string)-1]=0;
603 else if(strcmp(token,"env")==0) {
607 if(getenv(string)) strcat(toto,(char *)getenv(string));
610 else if(strcmp(token,"hms")==0) {
617 sprintf(string,"%s%02ld:%02ld:%02ld",string,hour,min,sec);
619 else if(strcmp(token,"dev")==0) {
620 strcat(string,device);
622 else if(strcmp(token,"cwd")==0) {
623 getcwd(string,STRINGL);
625 else if(strcmp(token,"baud")==0) {
626 strcat(string,cspeed);
628 else if(strcmp(token,"str")==0 || strcmp(token,"ltoa")==0) {
629 sprintf(string,"%s%ld",string,getvalue());
631 else if(strcmp(token,"hexu")==0) {
632 sprintf(string,"%s%lX",string,getvalue());
634 else if(strcmp(token,"hex")==0) {
635 sprintf(string,"%s%lx",string,getvalue());
637 else if(strcmp(token,"oct")==0) {
638 sprintf(string,"%s%lo",string,getvalue());
640 else if(strcmp(token,"dirname")==0) {
645 for(a=0;a<strlen(string);a++) {
646 if(string[a]=='/' || string[a]=='\\') b=a;
652 else if(strcmp(token,"tolower")==0) {
656 for(a=0;a<strlen(string);a++) {
657 if(string[a]>='A' && string[a]<='Z' ) string[a]=string[a]-'A'+'a';
662 else if(strcmp(token,"toupper")==0) {
666 for(a=0;a<strlen(string);a++) {
667 if(string[a]>='a' && string[a]<='z' ) string[a]=string[a]-'a'+'A';
672 else if(strcmp(token,"basename")==0) {
677 for(a=0;a<strlen(string);a++) {
678 if(string[a]=='/' || string[a]=='\\') b=a+1;
681 while(string[b]) toto[a++]=string[b++];
685 else if(strcmp(token,"script")==0) {
686 strcat(string,scriptfile);
688 else if(strcmp(token,"right")==0) {
694 if(b>strlen(string)) serror("String is shorter than second argument",7);
697 while(b!=0 && string[a]!=0) {
698 toto[c++]=string[a++];
704 else if(strcmp(token,"left")==0) {
710 if(b>strlen(string)) serror("String is shorter than second argument",7);
713 while(b!=0 && string[a]!=0) {
714 toto[c++]=string[a++];
720 else if(strcmp(token,"mid")==0) {
728 if(a>strlen(string)) serror("String is shorter than second argument",7);
730 while(b!=0 && string[a]!=0) {
731 toto[c++]=string[a++];
737 else if(strcmp(token,"sex")==0) {
738 strcat(string,"You're a naughty boy, you!");
740 else serror("Invalid string funtion",5);
743 else if(script[pc]=='$') {
744 strcat(string,stringvars[getstringindex()]);
746 else if(script[pc]=='"' || script[pc]=='\'') {
748 while(script[pc]!=match) {
750 if(ch==0) serror("Umatched quote.",5);
752 if(script[pc]<='7' && script[pc]>='0' &&
753 script[pc+1]<='7' && script[pc+1]>='0' ) {
755 while(script[pc]>='0' && script[pc]<='7') {
756 ch=8*ch+script[pc++]-'0';
762 case 't' : ch=9; break;
764 case 'r' : ch=13; break;
766 case 'n' : ch=10; break;
768 case 'b' : ch=8; break;
770 case 'f' : ch=12; break;
774 case '\\' : ch=script[pc]; break;
775 default : serror("Malformed escaped character",5);
782 if(ch!='^' && ch!='"' && ch!='\'' && ch!='\\' ) {
783 ch=ch&31; /* Control char */
791 pc++; /* Space over quote */
795 string[p++]=script[pc++];
801 /* Get a value, multiply by a hundred (for time values) */
802 unsigned long getdvalue(void) {
806 sscanf(token,"%f",&f);
807 f+=0.00001; /* Rounding errors */
815 if(script[pc]=='$') {
817 index=getstringindex();
819 else index=getintindex();
822 if(strcmp(token,"=")!=0) serror("Bad LET assignment, '=' missing",5);
826 strcpy(stringvars[index],string);
829 intvars[index]=getvalue();
833 /* See documentation for doXXX() functions */
834 int dowaitquiet(void) {
835 unsigned long timeout,timequiet,quiet,now;
837 timeout=htime()+getdvalue();
839 timequiet=htime()+quiet;
844 if(c!= -1) timequiet=now+quiet;
845 if(now>=timequiet) quit=0;
846 if(now>=timeout) quit=255;
851 int dowaitfor(void) {
852 char strings[20][80];
854 unsigned long timeout;
860 timeout=htime()+getdvalue();
861 while(script[pc]==',' || script[pc]=='$' || script[pc]=='"' ||
863 if(script[pc]==',') pc++;
866 strcpy(strings[b],string);
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';
877 while(htime()<timeout) {
879 //printf("Byte \"%c\" ",c);
882 if(c>='A' && c<='Z') c=c-'A'+'a';
884 for(a=0;a<127;a++) buffer[a]=buffer[a+1]; //shuffle down
887 while(strings[b][0]) {
888 c=strlen(strings[b]);
889 if (strcmp(strings[b],&buffer[127-c]) == 0){
899 /* Parse script for "on" or "off" wich are tokens, not strings */
900 BOOL getonoroff(void) {
904 if(strcmp(token,"on")==0) return(1);
905 if(strcmp(token,"off")==0) return(0);
908 if(a!=0 && a!=1) serror("Bad value (should be on or off, 1 or 0.)",5);
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);
921 struct termio console;
924 if(strcmp(token,"echo")==0) {
926 if(getonoroff()) a=ECHO|ECHOE;
927 if(ioctl(0, TCGETA, &console)<0) {
928 serror("Can't ioctl FD zero!\n",2);
930 console.c_lflag &= ~(ECHO | ECHOE);
931 console.c_lflag |= a;
932 ioctl(0, TCSETA, &console);
934 else if(strcmp(token,"senddelay")==0) {
935 senddelay=10000L*getdvalue();
937 else if(strcmp(token,"clocal")==0) {
939 if(getonoroff()) clocal=CLOCAL;
942 else if(strcmp(token,"umask")==0) {
943 umask(getvalue()&0777);
945 else if(strcmp(token,"verbose")==0) {
946 verbose=getonoroff();
948 else if(strcmp(token,"comecho")==0) {
949 comecho=getonoroff();
951 else if(strcmp(token,"ignorecase")==0) {
952 ignorecase=getonoroff();
954 else if(strcmp(token,"com")==0) {
956 if(script[pc]=='$' || script[pc]=='\'' || script[pc]=='"') {
958 strcpy(token,string);
963 while(token[b]>='0' && token[b]<='9') {
964 a=10*a+token[b++]-'0';
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);
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);
985 case '1': stopbits=0; break;
986 case '2': stopbits=CSTOPB; break;
987 default : serror("Stop bits can only be 1 or 2",5);
992 sprintf(cspeed,"%d",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;
1009 if(high_speed == 0) speed = B115200;
1010 else speed = B57600;
1013 case 460800: speed = B460800; break;
1014 default: serror("Invalid baudrate",1);
1024 for(a=0;a<labels;a++) {
1025 if(strcmp(token,label[a])==0) break;
1029 sprintf(msg,"Label \"%s\" not found",token);
1037 void dogosub(void) {
1039 if(preturn==MAXGOSUBS) serror("Reached maximum GOSUB depth",3);
1042 returns[preturn++]=pc;
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]=='$' ) {
1060 char stringarg[STRINGL];
1061 char tokencopy[MAXTOKEN];
1069 if(getonearg()!=1) serror("Comparison mis-match",7);
1070 if(strcmp(token,"<")==0) {
1071 if(intarg<number) ifres=1;
1073 if(strcmp(token,"<=")==0) {
1074 if(intarg<=number) ifres=1;
1076 else if(strcmp(token,"=")==0) {
1077 if(intarg==number) ifres=1;
1079 else if(strcmp(token,">")==0) {
1080 if(intarg>number) ifres=1;
1082 else if(strcmp(token,">=")==0) {
1083 if(intarg>=number) ifres=1;
1085 else if(strcmp(token,"<>")==0) {
1086 if(intarg!=number) ifres=1;
1088 else if(strcmp(token,"!=")==0 || strcmp(token,"<>")==0) {
1089 if(intarg!=number) ifres=1;
1093 strcpy(stringarg,string);
1095 strcpy(tokencopy,token);
1097 if(getonearg()!=0) serror("Comparison mis-match",7);
1098 if(strcmp(tokencopy,"<")==0) {
1099 if(strcmp(stringarg,string)<0) ifres=1;
1101 if(strcmp(tokencopy,"<=")==0) {
1102 if(strcmp(stringarg,string)<=0) ifres=1;
1104 else if(strcmp(tokencopy,"=")==0) {
1105 if(strcmp(stringarg,string)==0) ifres=1;
1107 else if(strcmp(tokencopy,">")==0) {
1108 if(strcmp(stringarg,string)>0) ifres=1;
1110 else if(strcmp(tokencopy,">=")==0) {
1111 if(strcmp(stringarg,string)>=0) ifres=1;
1113 else if(strcmp(tokencopy,"!=")==0 || strcmp(tokencopy,"<>")==0) {
1114 if(strcmp(stringarg,string)!=0) ifres=1;
1117 if(!ifres) skipline();
1120 int getindex(void) {
1123 if(index>='A' && index<='Z') index=index-'A'+'a';
1124 if(index>'z' || index<'a') serror("Malformed variable name",7);
1126 if(script[pc]>='0' && script[pc]<='9') {
1127 index=index+(1+script[pc++]-'0')*26;
1132 /* Parse script to find integer variable index */
1133 int getintindex(void) {
1135 if(script[pc]=='$') serror("Integer variable expected",7);
1139 /* Parse script to find string variable index and allocate memory for storage
1141 int getstringindex(void) {
1144 if(script[pc++]!='$') serror("String variable expected",7);
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;
1155 char terminators[STRINGL];
1159 unsigned long timeout;
1160 timeout=htime()+getdvalue();
1162 strcpy(terminators,string);
1163 index=getstringindex();
1167 while(goahead && htime()<timeout) {
1170 for(a=0;a<strlen(terminators);a++) {
1171 if(c==terminators[a]) goahead=0;
1173 if(goahead==0 && b==0) goahead=1; /* Ignore terminators if nothing yet */
1180 if(goahead) resultcode= -1;
1181 strcpy(stringvars[index],string);
1184 void doprint(int channel) {
1187 while(script[pc]!=' ' && script[pc]!='\t' && script[pc]!='\n') {
1188 if(script[pc]==',') pc++;
1190 if(script[pc]=='"' || script[pc]=='\'' || script[pc]=='$' ) {
1195 sprintf(string,"%ld",getvalue());
1201 case 1: printf("%s",msg); fflush(stdout); break;
1202 case 2: fputs(msg,stderr); break;
1204 if(msg[strlen(msg)-1]=='\n') msg[strlen(msg)-1]=0;
1208 if(filep==NULL) serror("File not opened",4);
1214 void doclose(void) {
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);
1226 else if(strcmp(token,"com")==0) {
1227 if(comfd== -1) serror("Com device not open",1);
1228 vmsg("Closing com fd");
1232 else if(strcmp(token,"file")==0) {
1233 if(filep==NULL) serror("Log file not open",4);
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);
1248 if (ioctl (comfd, TCGETA, &svbuf) < 0) {
1249 sprintf(msg,"Can't control %s, please try again.\n",device);
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;
1268 dormir(200000); /* Wait a bit (DTR raise) */
1269 sprintf(msg,"Opened %s as FD %d",device,comfd);
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);
1282 if (ioctl (comfd, TCGETA, &svbuf) < 0) {
1283 sprintf(msg,"Can't ioctl get device %s.\n",device);
1286 ioctl(comfd, TCGETA, &stbuf);
1287 speed=stbuf.c_cflag & CBAUD;
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;
1303 if (high_speed == 0) strcpy(cspeed,"115200");
1304 else strcpy(cspeed,"57600");
1307 case B460800: strcpy(cspeed, "460800");break;
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;
1321 dormir(200000); /* Wait a bit (DTR raise) */
1322 sprintf(msg,"Opened %s as FD %d",device,comfd);
1328 if(strcmp(token,"com")==0) {
1330 if(script[pc]=='$' || script[pc]=='\'' || script[pc]=='"') {
1333 else gethardstring();
1334 strcpy(device,string);
1337 else if (strcmp(token,"file")==0) {
1338 if(filep!=NULL) serror("File already open",4);
1340 if((filep=fopen(string,"a"))==NULL) serror("Could not open file",4);
1342 else serror("OPEN only takes com or file argument",5);
1345 int doscript(void) {
1351 if(script[pc]=='\n') pc++;
1354 if(verbose) printwhere();
1355 if(gettoken()) serror("Could not gettoken()",5);
1356 if(strcmp(token,"rem")==0) {
1359 else if (strcmp(token,"label")==0) {
1360 skiptoken(); /* Get rid of keyword */
1362 else if(strcmp(token,"open")==0) {
1365 else if(strcmp(token,"opengt")==0) {
1368 else if(strcmp(token,"close")==0) {
1371 else if(strcmp(token,"exec")==0) {
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);
1378 else if(strcmp(token,"exit")==0) {
1381 else if(strcmp(token,"testkey")==0) {
1384 else if(strcmp(token,"kill")==0) {
1386 resultcode=kill(getvalue(),a);
1388 else if(strcmp(token,"fork")==0) {
1391 else if(strcmp(token,"hset")==0) {
1394 hset=htime()-getvalue();
1396 else if(strcmp(token,"cd")==0) {
1398 resultcode=chdir(string);
1400 else if(strcmp(token,"putenv")==0) {
1402 strcpy(line,string);
1403 resultcode=putenv(line); /* putenv can't read from global string[] */
1405 else if(strcmp(token,"wait")==0) {
1408 else if(strcmp(token,"system")==0) {
1412 else if(strcmp(token,"input")==0) {
1413 FILE *infd = fdopen(0,"r");
1414 fgets(stringvars[getstringindex()],1024,infd);
1417 else if(strcmp(token,"get")==0) {
1420 else if(strcmp(token,"print")==0) {
1423 else if(strcmp(token,"eprint")==0) {
1426 else if(strcmp(token,"lprint")==0) {
1429 else if(strcmp(token,"fprint")==0) {
1432 else if(strcmp(token,"if")==0) {
1435 else if(strcmp(token,"else")==0) {
1436 if(ifres) skipline();
1438 else if(strcmp(token,"gosub")==0) {
1441 else if(strcmp(token,"return")==0) {
1442 if(preturn==0) serror("RETURN without gosub",5);
1443 pc=returns[--preturn];
1445 else if(strcmp(token,"goto")==0) {
1448 else if(strcmp(token,"waitfor")==0) {
1449 resultcode=dowaitfor();
1451 else if(strcmp(token,"waitquiet")==0) {
1452 resultcode=dowaitquiet();
1454 else if(strcmp(token,"set")==0) {
1457 else if(strcmp(token,"dec")==0) {
1458 intvars[getintindex()]--;
1460 else if(strcmp(token,"inc")==0) {
1461 intvars[getintindex()]++;
1463 else if(strcmp(token,"let")==0) {
1466 else if(strcmp(token,"dump")==0) {
1469 else if(strcmp(token,"abort")==0) {
1473 else if(strcmp(token,"send")==0) {
1477 else if(strcmp(token,"flash")==0) {
1486 else if(strcmp(token,"sleep")==0) {
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. */
1493 /* Humour is the spice of life. */
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;
1506 while(script[pc]=='\n') pc++;
1511 int main(int argc,char **argv) {
1513 int aa,b,i,skip_default;
1515 unsigned char terminator='\n';
1518 strcpy(device,GTDEVICE);
1526 ioctl(1, TCGETA, &cons);
1527 if((script=( char *)malloc(scriptspace))==NULL) {
1528 serror("Could not malloc()",3);
1530 for(a=0;a<NVARS;a++) {
1532 stringvars[a]=NullString;
1537 for(a=0;a<strlen(argv[0]);a++) {
1538 if(argv[0][a]=='/') b=a+1;
1540 while((aa=getopt(argc,argv,"xhevd:t:sb:"))!= -1) {
1546 terminator=optarg[0];
1547 sprintf(msg,"Alternate line terminator set to \"%c\"",terminator);
1551 strcpy(device,optarg);
1556 vmsg("Communication echo turned on");
1560 vmsg("Verbose output enabled");
1566 printf("gcom version 0.3 Copyright Paul Hardwick (c) 2005 \n");
1567 printf("\nType 'gcom help' for more information\n");
1571 printf("High speed overide (115200 is now 57600).\n");
1579 strcpy(scriptfile,argv[optind++]);
1580 sprintf(msg,"Script file: %s",scriptfile);
1585 code = get_code(scriptfile);
1587 scriptspace=strlen(code)+2;
1588 if((script=( char *)realloc(script,scriptspace))==0) {
1589 serror("Could not malloc()",3);
1591 strcpy(script,code);
1592 for(aa=0;aa<scriptspace;aa++) {
1593 if(script[aa]==terminator) script[aa]='\n';
1595 //scriptfile[0] = '\0';
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);
1604 strcpy(script,code);
1605 for(aa=0;aa<scriptspace;aa++) {
1606 if(script[aa]==terminator) script[aa]='\n';
1608 //scriptfile[0] = '\0';
1610 if((fp=fopen(scriptfile,"r"))==NULL) {
1611 sprintf(msg,"Could not open scriptfile \"%s\".\n",scriptfile);
1616 script[i++]='\n'; script[i]=0;
1618 while((fgets(line,STRINGL-1,fp))!=NULL) {
1620 if((scriptspace-i)<STRINGL) {
1621 scriptspace+=STRINGL+STRINGL;
1622 if((script=(char *)realloc(script,scriptspace))==NULL) {
1623 serror("Could not realloc()",3);
1626 for(aa=0;aa<b;aa++) {
1628 if(script[i]==terminator) script[i]='\n';
1638 while((script[i]=='\n' || script[i]==' ' || script[i]=='\t') && i!=0) i--;
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);
1654 if(strcmp(token,"label")==0) {
1656 for(aa=0;aa<labels;aa++) {
1657 if(strcmp(token,label[aa])==0) {
1659 serror("Duplicate label",5);
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);
1673 sprintf(msg,"argc:%d",argc);
1675 for(aa=0;aa<argc;aa++) {
1676 sprintf(msg,"argv[%d]=%s",aa,argv[aa]);
1679 vmsg(" ---Script---");
1682 if(ch=='\n' && script[aa]!=0) {
1683 fprintf(stderr,"%4d@%04d ",++b,aa);
1688 vmsg(" ---End of script---");
1692 fprintf(stderr,"No script!\n");
1698 if(comfd!= -1) close(comfd);
1699 sprintf(msg,"Exit with code %d.\n",a);