I64 A2I64(U8 *st,I64 radix=10,U8 **_end_ptr=NULL) {//ASCII to I64. Similar to strtoul(). //Allows radix change with "0x20" "0b1010" "0d123" "0o18". //Be careful of A2I64("0b101",16)-->0xB101. Bool neg=FALSE; I64 ch,result=0; if (!st || !(2<=radix<=36)) { if (_end_ptr) *_end_ptr=st; return 0; } while (Bt(chars_bitmap_white_space,*st)) st++; while (TRUE) switch (*st) { case '-': st++; neg=!neg; break; case '+': st++; break; case '0': st++; ch=ToUpper(*st); if (ch>='B' && (radix<=10 || ch>'A'+radix-11)) switch (ch) { case 'B': radix=2; st++; break; case 'O': radix=8; st++; break; case 'D': radix=10; st++; break; case 'X': radix=16; st++; break; } default: goto ai_cont; } ai_cont: while (ch=ToUpper(*st++)) { if (radix>10) { if ('0'<=ch<='9') result=result*radix+ch-'0'; else if ('A'<=ch<='A'+radix-11) result=result*radix+ch-'A'+10; else break; } else if ('0'<=ch<='0'+radix-1) result=result*radix+ch-'0'; else break; } if (_end_ptr) *_end_ptr=st-1; if (neg) return -result; else return result; } F64 A2F64(U8 *src,U8 **_end_ptr=NULL) {/*ASCII string to F64. Does not allow more than 18-digits before or after the decimal point because the numbers before and after the decimal point are stored in 64-bits. Use exponentiated forms to avoid this. */ I64 i,j,k,ch; F64 d; Bool neg=FALSE,neg_e=FALSE; ch=*src++; while (Bt(chars_bitmap_white_space,ch)) ch=*src++; if (ch=='-') { neg=TRUE; ch=*src++; } if (!StrNCmp(src-1,"inf",3)) { d=ì; src+=3; goto a2f_end; } if (*src=='ì') { d=ì; src++; goto a2f_end; } i=0; while (TRUE) { if (Bt(chars_bitmap_dec_numeric,ch)) i=i*10+ch-'0'; else { if (ch=='.' || ch=='e' || ch=='E') break; d=i; goto a2f_end; } ch=*src++; } if (ch=='.') ch=*src++; k=0; while (TRUE) { if (Bt(chars_bitmap_dec_numeric,ch)) { i=i*10+ch-'0'; k++; } else { if (ch=='e' || ch=='E') break; d=i*Pow10I64(-k); goto a2f_end; } ch=*src++; } ch=*src++; if (ch=='-') { neg_e=TRUE; ch=*src++; } j=0; while (TRUE) { if (Bt(chars_bitmap_dec_numeric,ch)) j=j*10+ch-'0'; else { if (neg_e) d=i*Pow10I64(-j-k); else d=i*Pow10I64(j-k); goto a2f_end; } ch=*src++; } a2f_end: if (_end_ptr) *_end_ptr=src-1; if (neg) return -d; else return d; } /* A2Date() This routine recognizes the following formats: 1) "*+nnnn" "*-nnnn" 2) mm/dd 3) mm/dd/yy It also supports some funs SM() start of mon EM() end of mon SM() start of year EY() end of year Full expressions are not implimented but you can do stuff like SM(*-7)+3 and it will return the 3rd day after the start of mon for seven days before today. */ CDate A2Date(U8 *_src) //ASCII date to CDate { CDate result=0; CDateStruct ds; U8 *src=MStrUtil(_src,SUF_REM_SPACES|SUF_TO_UPPER), *v=StrNew(src), *p1=src; Bool start_mon=FALSE,end_mon=FALSE, start_year=FALSE,end_year=FALSE; MemSet(&ds,0,sizeof(CDateStruct)); if (!StrNCmp(p1,"SM(",3)) { p1+=3; start_mon=TRUE; } else if (!StrNCmp(p1,"EM(",3)) { p1+=3; end_mon=TRUE; } else if (!StrNCmp(p1,"SY(",3)) { p1+=3; start_year=TRUE; } else if (!StrNCmp(p1,"EY(",3)) { p1+=3; end_year=TRUE; } if (*p1=='*') { p1++; if (*p1=='+' || *p1=='-') result.date=A2I64(p1,,&p1); result+=Now+local_time_offset; } else { StrFirstRem(p1,"/",v); //Put mon into v ds.mon=A2I64(v); if (StrOcc(p1,'/')) { StrFirstRem(p1,"/",v); //Put day into v leaving year in p1 ds.day_of_mon=A2I64(v); ds.year=A2I64(p1,,&p1); if (ds.year<100) //if not 4 digit year ds.year+=2000; } else { ds.day_of_mon=A2I64(p1,,&p1); ds.year=Year; } result=Struct2Date(&ds); } if (*p1==')') p1++; if (start_mon) result.date=FirstDayOfMon(result.date); else if (end_mon) result.date=LastDayOfMon(result.date); else if (start_year) result.date=FirstDayOfYear(result.date); else if (end_year) result.date=LastDayOfYear(result.date); if (*p1=='+' || *p1=='-') result.date+=A2I64(p1); Free(src); Free(v); return result-local_time_offset; } U8 *ScanJoin(U8 *src,U8 *fmt,I64i argc,I64i *argv) //Pass ptr to data, //For %s pass ptr to ptr (be careful because addr //of array is the same as array--create ptr to array and take addr { U8 ch,*buf,*ptr,**pptr; Bool left_justify=FALSE; I64 cur_arg=0,i,len,*i_ptr,dec_len; F64 *d_ptr; if (!fmt) throw('Scan'); while (ch = *fmt++) { if (ch=='%') { if (*fmt=='%') { src++; fmt++; } else { if (*fmt=='-') { left_justify=TRUE; fmt++; } else left_justify=FALSE; len=0; while ('0'<=*fmt<='9') len=len*10+ (*fmt++ -'0'); if (*fmt=='*') { fmt++; if (cur_arg>=argc) throw('Scan'); len=argv[cur_arg++]; } ch=*fmt++; if (ch && !len) { ptr=src; while (*ptr && *ptr!=*fmt) ptr++; len=ptr-src; } else { if (ch=='.') { dec_len=0; while ('0'<=*fmt<='9') dec_len=dec_len*10+ (*fmt++-'0'); if (*fmt=='*') { fmt++; if (cur_arg>=argc) throw('Scan'); dec_len=argv[cur_arg++]; } ch=*fmt++; } } buf=MAlloc(len+1); for (i=0;i=argc) throw('Scan'); pptr=argv[cur_arg++]; StrCpy(*pptr,buf); break; case 'c': if (cur_arg>=argc) throw('Scan'); ptr=argv[cur_arg++]; *ptr=*buf; break; case 'C': if (cur_arg>=argc) throw('Scan'); ptr=argv[cur_arg++]; *ptr=ToUpper(*buf); break; case 'z': if (cur_arg+1>=argc) throw('Scan'); i_ptr=argv[cur_arg++]; *i_ptr=LstMatch(buf,argv[cur_arg++]); break; case 'Z': if (cur_arg+1>=argc) throw('Scan'); i_ptr=argv[cur_arg++]; *i_ptr=DefineMatch(buf,argv[cur_arg++]); break; case 'd': if (cur_arg>=argc) throw('Scan'); i_ptr=argv[cur_arg++]; *i_ptr=A2I64(buf); break; case 'X': if (cur_arg>=argc) throw('Scan'); i_ptr=argv[cur_arg++]; *i_ptr=A2I64(buf,16); break; case 'b': if (cur_arg>=argc) throw('Scan'); i_ptr=argv[cur_arg++]; *i_ptr=A2I64(buf,2); break; case 'e': case 'f': case 'g': case 'n': if (cur_arg>=argc) throw('Scan'); d_ptr=argv[cur_arg++]; *d_ptr=A2F64(buf); break; case 'D': if (cur_arg>=argc) throw('Scan'); i_ptr=argv[cur_arg++]; *i_ptr=A2Date(buf); break; } Free(buf); } } else src++; } return src; } U8 *Scan(U8 *src,U8 *fmt,...) //Pass ptr to data, //For %s pass ptr to ptr (be careful because addr //of array is the same as array--create ptr to array and take addr { return ScanJoin(src,fmt,argc,argv); }