/****************************************************************************** * * METAL library functions for VERSION 1.20a * * FILE: HMLIB.C version 1.20a * * * Copyright (c) 1984 Tim Gary * Delphi Data Systems * All rights reserved. * * * Common utility finctions used in METAL, MENTER and MUTIL * ****************************************************************************** * * 1.20a 11/04/84 Counters routines made less dependant upon right info. * 1.10e 11/02/84 Added to pcounters routine, now wil write to specified file * if arg!=0. Put writestat routine here, for easy access. * 1.10e 10/30/84 Parsing routine fixed to zap trailing blanks in ask func. * Future note: CAN'T change in getline!!!!!!!! * * 1.10c 10/0x/84 Hayes clock date order changed to reasonable mm/dd/yy form. * * 1.10b * 1.10a 8/31/84 Overlay stuff started. * * 1.01a 6/27/84 Multi user stuff inserted. * 1.01a 6/10/84 Setup for Aztec C 1.06. CCS clock stuff added. * * 1.0c 5/17/84 Added Hayes clock support. * * 1.0b 4/20/84 (continued) Added usindex() (index ignoring case), distext() * 1.0b 4/14/84 (continued) Findbye routine setup.. * 1.0b 4/13/84 Added Upper/lower case routines. Added Novice user help. * Putchar returns char typed at [More] prompt for checking. * Removed several MENTER only functions (putcaller, writestat..) * External height variable used for screen height now. * * 1.0a 1/25/84 Added terminal height code. Now pauses with [more] prompt * * 1.0 1/17/84 Version 3.0a new format of files. * *****************************************************************************/ #include "xpm.h" #include "hmh.h" #include "hmconfg.h" #include "ctype.h" #define dgetchar getchar /******************************** * Return index into type table * ********************************/ get_type(t_char) char t_char; { register int i; for (i=0; O.user_type[i].type!='\0'; i++) if (O.user_type[i].type==t_char) break; if (O.user_type[i].type=='\0') --i; /* return last real type */ return i; } /******************************** * type a file, stop on a break * ********************************/ type(filename) char *filename; { FILE *fil; register int cfast; int c; if ((fil=open(filename,F_RD | F_UNLOCK))==NULL) return ERROR; /* open text file for read */ novhelp(); /* help novice if he is one */ read(fil,1); /* getc doesn't do this initially, sigh */ while ( (cfast=getc(fil))!=ERROR && cfast!=EOF ) { if (cfast!='\r') if (bcputchar(cfast)==ERROR) break; *(char *)O.RESETDRIVE; } close(fil); return NULL; } /******************************************************* * display text from pointer to array of char pointers * * (eg static char *it_hlp[] = { "1","2","3",0 }; )* *******************************************************/ dis_text(sp) register char **sp; { while (*sp && (send(*sp++)!=ERROR)); } /* A one liner to help novices out on the system */ novhelp() { if (user.parm.expert==POFF) send("\nControl-K to cancel, Control-S to pause.\n"); } /* Regular old putchar, but checks for break (^K, etc..) chars. Returns ERROR if one hit, else it returns the char */ bcputchar(ch) int ch; { register int a; if (!breakkey()) { if ( ((a=toupper(putchar(ch)))=='N') || ((a & 0x1f)==0xb) ) a=ERROR; } else a=ERROR; return a; } send(s) /* send string while checking for break */ register char *s; { while (*s) if (bcputchar(*s++)==ERROR) return ERROR;; return 0; /* else ok */ } /**************************************** * Print string to printer (LST:) * ****************************************/ print(str) register char *str; { while (*str) bdos(5,*str++); } /******************************** * check for ^k ^x, ^s, etc.. * ********************************/ breakkey() /* check for break */ { register int key; if (key=bdos(6,0xff)) { if (((key & 0x1f)==0xb) /* stop if ^K, ^X, etc.. */ || ((key & 0x1f)==0x18)) { putchar('\n'); return ERROR; } if ((key & 0x1f)==0x13) /* pause if ^S */ getd(); globalchar=key; /* save the char for later reference */ } return 0; /* none pressed */ } /****************************************************************************** * ask: get string after prompting user. * * question= prompt string (will NOT be printed if ';' used * to get mult. commands/options.. * str = place to put string * maxchars= max # of chars to be accepted from terminal * options = following BITs that may be combined: * UPLOW : accept upper/lower case input * UP : upper case conversion is made * NOECHO : turn off display of chars as they are entered * NUMBER : a 'position' number is output instead of chars typed * MSGLINE : ONLY FOR getl(*).. for it to accept MAXMSGLINE chars * *****************************************************************************/ ask(question,str,maxchars,options) char *question,*str; int maxchars; register char options; { register char *temp,*temp1; if ((strloc==0) || (glbstr[strloc]=='\0')) { send(question); /* ask the question */ getl(glbstr,options); /* get the line */ strloc=0; /* make sure of this */ } /* now that we have line input */ temp1=0xffff; /* initial not found flag */ temp=index(&glbstr[strloc],';'); if (temp==0) temp=0xffff; /* convert 0 to ffff for easy compare */ if (sepstr) { temp1=index(&glbstr[strloc],sepstr); if (temp1==0) temp1=0xffff; } if (temp!=temp1) /* if not both 0xffff */ temp=maxchars) glbstr[strloc+maxchars]='\0'; /* same here */ if (options & UP) upcase(&glbstr[strloc]); /* all upper case if spec'd */ strcpy(str,&glbstr[strloc]); /* copy it to where it's wanted */ if (temp!=0xffff) strloc=(temp-glbstr)+1; /* updates strloc if ';' */ else strloc=0; /* else start over */ /* kill trailing blanks */ /* for (temp=str+strlen(str); temp!=str && isspace(*temp); *(temp--)='\0'); */ } /* ask */ /* read a line of input from console */ getl(s,options) char *s,options; { register char c; register int llen; char *temp; register int count; if (options&MSGLINE) llen=O.MAXMSGLINE; else llen=MAXLINE; temp=s; count=0; s=temp; if ((user.parm.bell)==PON) putchar(7); /* ring bell */ while ((c=getd()) != '\n' && c !='\r' ) { if (c=='\b' || c==0x7f) { /* backspace or DEL */ if (!count) continue; --count; --s; if (!(options & NOECHO) || (options & NUMBER)) send("\b \b"); continue; } if (c>31) /* tab goes in directly */ { if (count=llen-4) putchar(7); } if (c==9) { if (count+1631) putchar(c); } else if ((options & NUMBER) != 0) putchar( (count % 10)+'0'); } /* while */ *s='\0'; /* end of string */ putchar('\n'); return temp; } static char line=1; /* current line (relative to last input) */ /************** * New putchar that counts columns *************/ putchar(ch) register int ch; { static int pos=0; /* position on line */ static char lastchar='\0'; register int i,c; c=NULL; /* returned character for MORE prompt */ if (ch=='\t') /* check for tab and expand */ { for (i = 0; i <= (pos+8)-((pos+8) & 0xf8); i++) putchar(' '); return; } if (ch=='\n') { pos=0; line++; bdos(6,'\r'); bdos(6,ch); } else { if (ch>=' ') pos++; bdos(6,ch); } if (ch=='\r') pos=0; /* reset posistion on line to zip */ if (line>=height && height!=0) { line=1; printf("[more]"); c=getd(); /* get char which clears lines */ printf("\r \r"); } return c; } /* new putchar */ /* new getchar to clear line variable, etc.. */ getchar() { register int cfast; putchar((cfast=getd())); /* freaky eh? */ return cfast; } getd() { register int cfast; line=1; while(!(cfast=bdos(6,0xff))); return cfast; } /************************************************************************ * To add your own clock routine, define the RTC clock setup to COMPUPRO or * HAYES then change the routine below to read your clock board, and put the * time and date (formated hh:mm:ss and mm-dd-yy) in the variables * (character pointers) time and date. ************************************************************************/ /*********************************************** * CompuPro/xxx and Hayes read clock functions * ***********************************************/ readclock() { #ifndef NOSS1 /* to make code smaller.. allow only certain clocks... */ /* compupro/ccs variables */ static char x[2] = "\0"; static int p[12] = { 5,4,3,2,1,0,10,9,8,7,12,11 }; /* commands */ register int i; *time=*date='\0'; /* null strings */ if (O.RTC==COMPUPRO /* || O.RTC==CCS */ ) { for (i=0; i<12; i++) { /* if (O.RTC==CCS) { out((char)O.CLKCMD,p[i]|0x40); hold digit while (in((char)O.CLKDATA) & 0x40); wait til held } */ out((char)O.CLKCMD,p[i]+0x10); /* if (O.RTC==CCS) while (in((char)O.CLKDATA) & 0x80); *//* ok data wait */ *x=in((char)O.CLKDATA)+'0'; /* if (O.RTC==CCS) out(O.CLKCMD,0); */ /* clear wait flag */ if (i==0) (*x)-=8; if (i<6) { if ( (i==2) || (i==4) ) strcat(time,":"); /* add a ':' above, for looks */ strcat(time,x); /* and always add the digit */ } else { if ( (i==8) || (i==10) ) strcat(date,"-"); strcat(date,x); } } /* for loop */ } /* end of compupro routine */ else #endif /* no ss1/ccs */ #ifndef NOHAYES if (O.RTC==HAYES) /* hayes chronogragh */ { char tdate[DATELEN+1]; outpstr(O.CLKCMD,O.CLKOMASK,O.CLKDATA,"\r\r\r\r\rATVD-\r"); inpstr(O.CLKCMD,O.CLKIMASK,O.CLKDATA,'\r',2,date); outpstr(O.CLKCMD,O.CLKOMASK,O.CLKDATA,"\r\r\r\r\rATVT:\r"); inpstr(O.CLKCMD,O.CLKIMASK,O.CLKDATA,'\r',2,time); for (i=0; i<500; i++); outpstr(O.CLKCMD,O.CLKOMASK,O.CLKDATA,"\r\r\r\r\rATRD\r"); inpstr(O.CLKCMD,O.CLKIMASK,O.CLKDATA,'\r',9,tdate); /* get date */ outpstr(O.CLKCMD,O.CLKOMASK,O.CLKDATA,"\r\r\r\r\rATRT\r"); inpstr(O.CLKCMD,O.CLKIMASK,O.CLKDATA,'\r',9,time); /* get time */ tdate[2]='\0'; tdate[8]='\0'; sprintf(date,"%s/%s",tdate+3,tdate); /* change to mm/dd/yy */ } /* Hayes.. */ #endif /* nohayes */ } /* readclock */ getdate() { if (O.RTC!=NOCLOCK) readclock(); else askdate(); return date; } /************************************* * output string to port specified. * * expected is: 1) status port * * 2) data out mask 3) data port * * 4) the string to be sent * * note: nulls may not be sent via * * this routine!! 0 terminates str * * if data/status>255 then memory * * mapped i/o is performed * *************************************/ outpstr(stat,stmask,data,string) unsigned stat,data; char stmask; register char *string; { while (*string) outchar(stat,stmask,data,*string++); } outchar(stat,stmask,data,c) register unsigned stat,data; char stmask,c; { if (stat>255) { while (!( (*(char *)stat & stmask))); *(char *)data=c; } else { while (!( in((char)stat) & stmask)); out((char)data,c); } } /******************************** * input string from port... * * parms: 1) status port * * 2) status mask 3) data port * * 4) end of string char * * 5) max chars over all * * 6) string pointer to place * * string * * note: same as above for * * memory mapped ports.. * ********************************/ inpstr(stat,stmask,data,eos,max,string) unsigned stat,data,max; char stmask,eos; register char *string; { char inpchar(); *(string+max)='\0'; /* make sure of termination */ while (max--) { *string=inpchar(stat,stmask,data) & 0x7f; if (*(string++)==eos) { *(string-1)='\0'; /* terminate, and abort */ break; } } } /* inpstr */ char inpchar(stat,stmask,data) register unsigned stat,data; char stmask; { unsigned to=50000; while ( to-- && !( ((stat>255) ? *(char *)stat : in((char)stat)) & stmask) ); return ( (data>255) ? *(char *)data : in((char)data) ); } /* get date from keyboard (for those without a clock) */ askdate() { char temp[2]; strcpy(time,"00:00:00"); sprintf(buffer,"Is %s today's date (y/n)?",*date=='\0' ? "00/00/00" : date); ask(buffer,temp,1,UP); if (*temp=='Y') return date; do ask("What's todays date (mm/dd/yy)? ",date,DATELEN,UP); while (strlen(date)!=DATELEN-1); } /* askdate */ /************************************************************************ * String functions... */ /* convert string to all upper case */ upcase(str) register char *str; { for (;*str;++str) *str=toupper(*str); } /* check for a space in the given string (returns 1 if space, else 0) */ isspc(str) register char *str; { while(*str) if (*str++<=' ') return TRUE; /* return TRUE if space/cntrl */ return FALSE; /* else FALSE returned */ } /* capitalize a string (all words in the string */ capstr(str) char *str; { register char *tp; *str=toupper(*str); /* first char is easy */ for ( tp=str; tp0); s1++, s2++, n--) if (*s1=='\0') return (toupper(*s1)-toupper(*s2)); /* if at end of first string, test for=length/return */ return (n ? (toupper(*s1)-toupper(*s2)) : 0); } /***************************** * Same as index(s,c), but with two strings *****************************/ sindex(s1,s2) register char *s1,*s2; { register char *sp; for (sp=s2; strlen(s1)<=strlen(sp); sp++) if (!strncmp(s1,sp,strlen(s1))) return sp; return 0; /* no match */ } /***************************** * Same as sindex(s1,s2), but IGNORE CASE in comparison *****************************/ usindex(s1,s2) char *s1,*s2; { register char *sp; for (sp=s2; strlen(s1)<=strlen(sp); sp++) if (!ustrncmp(s1,sp,strlen(s1))) return sp; return 0; /* no match */ } /* get the counters from counters file */ gcntrs(f) char *f; { char tdate[DATELEN+1]; #ifndef MULTI_USER int id_num; /* make dumby local copy if single user */ #endif /* in case of failure.... */ callnum=id_num=0; /* for defaults in case nothing found */ if ((counters=open(f ? f : COUNTERS,F_RD | F_LOCK))!=0) { read(counters,0); sscanf(bufloc(counters),"%d %d %d %s %d %d",&msgcount, &callnum,&nextmsg,(O.RTC ? tdate : date),&id_num,&privmsgs); #ifdef TURBODOS if (strncmp(in_loc,ID_STR,3)) { sprintf(bufloc(counters),"%d %u %u %s %d %d",msgcount,callnum, nextmsg,date,++id_num,privmsgs); write(counters,0); strcpy(id_loc,ID_STR); *(id_loc+3)=(char)id_num; } #endif /* TurboDos */ close(counters); } } /* put the counters file on disk */ pcounters(f) char *f; { #ifndef MULTI_USER int id_num=0; #endif counters=open(f ? f : COUNTERS,F_RW | F_LOCK); sprintf(bufloc(counters),"%d %u %u %s %d %d",msgcount,callnum, nextmsg,date,id_num,privmsgs); write(counters,0); close(counters); } /* write user specified to correct place in users file, 0=write to current possition in the OPEN users file */ putuser(un) register unsigned un; { register int *tnum; register int flag; if (un!=0) /* EXPECTS user file to already be open if nu=0 */ { if ((users=open(USERFILE,F_RW | F_LOCK))==NULL) return ERROR; /* else, open it */ tnum=bufloc(users); /* pointer to user # */ do flag=read(users,1); while (*tnum!=un && flag==128); /* til match, or eof.. */ if (flag==128) setrrec(users,-1); /* if not eof, backup one */ } /* end nu>0 routine */ movmem(&user,bufloc(users),128); /* get user vars */ write(users,0); /* write record, no increment... */ close(users); /* either method called closes the users file */ return NULL; /* NULL=all's well */ } /* write user, and 8 char stat parm to status line if available */ wustat(s) char *s; { char buf[128]; sprintf(buf,"%8s -- %s %s - '%c' %s -- %s",s ? s : "",user.first, user.last,user.status,time,user.city); writestat(buf); } /* output string to the 25th status line.. */ writestat(str) register char *str; { if (O.STATUSLINE) /* 25th line status display on???? */ { if (O.OSMASK) { outpstr(O.OSTAT,O.OSMASK,O.ODATA,O.TO25); /* get to 25th line */ outpstr(O.OSTAT,O.OSMASK,O.ODATA,str); /* output string */ outpstr(O.OSTAT,O.OSMASK,O.ODATA,O.FROM25); /* get back */ } else { /* otherwise O.ODATA is address of output routine BIOS DEP! */ outsbios(O.TO25); outsbios(str); outsbios(O.FROM25); } } } outsbios(s) register char *s; { while (*s) outcbios(*s++); } char glob_ch; /* so I can find the char easily */ char *glob_ad; outcbios(c) register char c; { glob_ch=c; glob_ad=O.ODATA; #asm lda glob_ch_ mov c,a sillyk: lxi d,sillyk+8 ; terrible kluge, don not change following push d ; instructions without changing this too!!! lhld glob_ad_ pchl nop #endasm } /* EOF hmlib.c */