U8 hex_digits[16]="0123456789ABCDEF"; U8 *Bin2Hex(U8 *dst,I64 n;I64 width) { U8 *result=dst+width; dst=result; while (width--) { *--dst=hex_digits[n&15]; n>>=4; } return result; } U0 PutHex(I64 n,I64 width) { U8 buf[17]; if (width>16) width=16; *Bin2Hex(buf,n,width)=0; "%s",buf; } asm { USE64 // ************************************ // IN: RAX=NUM TO PRINT PUT_HEX_U64:: PUSH_C_REGS PUSH 16 PUSH RAX CALL &PutHex POP_C_REGS RET PUT_HEX:: PUT_HEX_U32:: PUSH_C_REGS PUSH 8 PUSH RAX CALL &PutHex POP_C_REGS RET PUT_HEX_U16:: PUSH_C_REGS PUSH 4 PUSH RAX CALL &PutHex POP_C_REGS RET PUT_HEX_U8:: PUSH_C_REGS PUSH 2 PUSH RAX CALL &PutHex POP_C_REGS RET // ************************************ PUT_CHAR:: // IN: RAX=Char PUSH_C_REGS PUSH RAX CALL &PutChar POP_C_REGS RET PUT_STR:: // IN: RSI=String PUSH_C_REGS PUSH RSI CALL &PutS POP_C_REGS RET // ************************************ _STRCAT:: ENTER 0 PUSH RSI PUSH RDI MOV RSI,U64 SF_ARG1[RBP] @@05: LODSB TEST AL,AL JNZ @@05 MOV RDI,RSI DEC RDI MOV RSI,U64 SF_ARG2[RBP] TEST RSI,RSI JZ @@15 @@10: LODSB STOSB TEST AL,AL JNZ @@10 @@15: POP RDI POP RSI LEAVE RET1 16 // ************************************ _STRCPY:: ENTER 0 PUSH RSI PUSH RDI MOV RDI,U64 SF_ARG1[RBP] TEST RDI,RDI JZ @@15 MOV RSI,U64 SF_ARG2[RBP] TEST RSI,RSI JNZ @@05 XOR RAX,RAX JMP @@10 @@05: LODSB @@10: STOSB TEST AL,AL JNZ @@05 @@15: POP RDI POP RSI LEAVE RET1 16 // ************************************ _STRCMP:: ENTER 0 PUSH RSI PUSH RDI MOV RSI,U64 SF_ARG2[RBP] MOV RDI,U64 SF_ARG1[RBP] @@05: LODSB TEST AL,AL JZ @@20 SCASB JE @@05 JA @@15 @@10: MOV RAX,1 JMP @@25 @@15: MOV RAX,-1 JMP @@25 @@20: SCASB JNE @@10 XOR RAX,RAX @@25: POP RDI POP RSI LEAVE RET1 16 // ************************************ TO_UPPER:: CMP AL,'a' JB @@05 CMP AL,'z' JA @@05 ADD AL,'A'-'a' @@05: RET // ************************************ _STRICMP:: ENTER 0 PUSH RSI PUSH RDI MOV RSI,U64 SF_ARG2[RBP] MOV RDI,U64 SF_ARG1[RBP] @@05: LODSB TEST AL,AL JZ @@30 CMP AL,'a' JB @@10 CMP AL,'z' JA @@10 ADD AL,'A'-'a' @@10: MOV BL,U8 [RDI] INC RDI CMP BL,'a' JB @@15 CMP BL,'z' JA @@15 ADD BL,'A'-'a' @@15: CMP AL,BL JE @@05 JA @@25 @@20: MOV RAX,1 JMP @@35 @@25: MOV RAX,-1 JMP @@35 @@30: MOV BL,U8 [RDI] TEST BL,BL JNE @@20 XOR RAX,RAX @@35: POP RDI POP RSI LEAVE RET1 16 // ************************************ _STRNCMP:: ENTER 0 PUSH RSI PUSH RDI MOV RCX,U64 SF_ARG3[RBP] MOV RSI,U64 SF_ARG2[RBP] MOV RDI,U64 SF_ARG1[RBP] @@05: TEST RCX,RCX JZ @@25 DEC RCX LODSB TEST AL,AL JZ @@20 SCASB JE @@05 JA @@15 @@10: MOV RAX,1 JMP @@30 @@15: MOV RAX,-1 JMP @@30 @@20: MOV BL,U8 [RDI] TEST BL,BL JNE @@10 @@25: XOR RAX,RAX @@30: POP RDI POP RSI LEAVE RET1 24 // ************************************ _STRNICMP:: ENTER 0 PUSH RSI PUSH RDI MOV RCX,U64 SF_ARG3[RBP] MOV RSI,U64 SF_ARG2[RBP] MOV RDI,U64 SF_ARG1[RBP] @@05: TEST RCX,RCX JZ @@35 DEC RCX LODSB TEST AL,AL JZ @@30 CMP AL,'a' JB @@10 CMP AL,'z' JA @@10 ADD AL,'A'-'a' @@10: MOV BL,U8 [RDI] INC RDI CMP BL,'a' JB @@15 CMP BL,'z' JA @@15 ADD BL,'A'-'a' @@15: CMP AL,BL JE @@05 JA @@25 @@20: MOV RAX,1 JMP @@40 @@25: MOV RAX,-1 JMP @@40 @@30: SCASB JNE @@20 @@35: XOR RAX,RAX @@40: POP RDI POP RSI LEAVE RET1 24 // ************************************ _STRMATCH:: ENTER 0 PUSH RSI PUSH RDI MOV RSI,U64 SF_ARG2[RBP] TEST RSI,RSI JZ @@25 MOV RDI,U64 SF_ARG1[RBP] TEST RDI,RDI JZ @@25 MOV DL,U8 [RDI] TEST DL,DL JZ @@20 JMP @@10 @@05: INC RSI @@10: LODSB TEST AL,AL JZ @@25 CMP AL,DL JNE @@10 DEC RSI MOV RCX,1 @@15: MOV AL,U8 [RDI+RCX] TEST AL,AL JZ @@20 CMP AL,U8 [RSI+RCX] JNE @@05 INC RCX JMP @@15 DEC RSI @@20: MOV RAX,RSI JMP @@30 @@25: XOR RAX,RAX @@30: POP RDI POP RSI LEAVE RET1 16 // ************************************ _STRIMATCH:: ENTER 0 PUSH RSI PUSH RDI MOV RSI,U64 SF_ARG2[RBP] TEST RSI,RSI JZ @@25 MOV RDI,U64 SF_ARG1[RBP] TEST RDI,RDI JZ @@25 MOV AL,U8 [RDI] CALL TO_UPPER MOV DL,AL TEST DL,DL JZ @@20 JMP @@10 @@05: INC RSI @@10: LODSB CALL TO_UPPER TEST AL,AL JZ @@25 CMP AL,DL JNE @@10 DEC RSI MOV RCX,1 @@15: MOV AL,U8 [RDI+RCX] CALL TO_UPPER TEST AL,AL JZ @@20 MOV BL,U8 [RSI+RCX] XCHG AL,BL CALL TO_UPPER CMP AL,BL JNE @@05 INC RCX JMP @@15 DEC RSI @@20: MOV RAX,RSI JMP @@30 @@25: XOR RAX,RAX @@30: POP RDI POP RSI LEAVE RET1 16 } _extern _STRCMP I64 StrCmp(U8 *st1,U8 *st2); _extern _STRICMP I64 StrICmp(U8 *st1,U8 *st2); _extern _STRNCMP I64 StrNCmp(U8 *st1,U8 *st2,I64 n); _extern _STRNICMP I64 StrNICmp(U8 *st1,U8 *st2,I64 n); _extern _STRMATCH U8 *StrMatch(U8 *pattern,U8 *st); _extern _STRIMATCH U8 *StrIMatch(U8 *pattern,U8 *st); _extern _STRCPY U0 StrCpy(U8 *dst,U8 *src); _extern _STRCAT U0 StrCat(U8 *dst,U8 *src); /* These bitmaps go to 0-511 so that $LK,"Lex","MN:Lex"$() can use them with $LK,"Token Codes","MN:TK_EOF"$. */ U32 alpha_bitmap[16]= {0x0000000,0x00000000,0x87FFFFFF,0x07FFFFFE,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}; U32 alpha_numeric_bitmap[16]= {0x0000000,0x03FF0000,0x87FFFFFF,0x07FFFFFE,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}; U32 alpha_numeric_no_at_bitmap[16]= {0x0000000,0x03FF0000,0x87FFFFFE,0x07FFFFFE,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}; U32 word_bitmap[16]= {0x0000000,0x03FF0080,0x87FFFFFE,0x07FFFFFE,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}; U32 filename_chars_bitmap[16]= {0x0000000,0x03FF73FB,0xEFFFFFFF,0x2FFFFFFF,0,0,0,0, 0,0,0,0,0,0,0,0}; U32 dec_numeric_bitmap[16]= {0x0000000,0x03FF0000,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}; U32 hex_numeric_bitmap[16]= {0x0000000,0x03FF0000,0x7E,0x7E,0,0,0,0, 0,0,0,0,0,0,0,0}; U32 white_space_bitmap[16]= {0x80003600,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}; U32 non_eol_white_space_bitmap[16]= {0x80001200,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}; U32 zero_cr_nl_cursor_bitmap[16]= {0x00002421,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}; U32 zero_tab_ff_cr_nl_cursor_bitmap[16]= {0x00003621,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}; U32 zero_tab_ff_cr_nl_cursor_dollar_bitmap[16]= {0x00003621,0x10,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}; U32 getkey_chars_bitmap[16]= {0x80002600,0xFFFFFFFF,0xFFFFFFFF,0x7FFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}; U32 printable_chars_bitmap[16]= {0x80003600,0xFFFFFFFF,0xFFFFFFFF,0x7FFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}; U32 displayable_chars_bitmap[16]= {0x80000000,0xFFFFFFFF,0xFFFFFFFF,0x7FFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}; U32 safe_dollar_chars_bitmap[16]= {0x80000000,0xFFFFFFEF,0xFFFFFFFF,0x7FFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0};//same but no dollar sign U32 non_eol_chars_bitmap[16]= {0xFFFFDBFE,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; U8 *LstSub(I64 sub, U8 *lst) {//Point to lst entry. //Not especially efficient but handy. Use an array of U8*'s for efficiency. if (!lst) return NULL; while (*lst && sub>0) { while (*lst) // Advance to end of cur entry. lst++; lst++; // Skip trailing zero if (*lst=='@') // Check for '@' alias lst entry lst++; else sub--; } if (sub||!*lst) return NULL; else return lst; } I64 LstMatch(U8 *pattern, U8 *lst,I64 flags=0) // RETURNS: -2 if Ambiguous, -1 if not found, else entry num { //Not especially efficient but handy. Use hash tables for efficiency. I64 n,sub=0,result=-1; U8 *ptr; Bool exact_match=FALSE; if (!lst) return -1; n=StrLen(pattern); while (*lst) { if (*lst=='@') { //Check for '@' alias lst entry sub--; lst++; } ptr=pattern; if (flags & LMF_IGNORE_CASE) while (*ptr && ToUpper(*ptr)==ToUpper(*lst)) { ptr++; lst++; } else while (*ptr && *ptr==*lst) { ptr++; lst++; } if (!*ptr) { // Did we reach end of pattern if (!*lst) // Did we reach end of lst entrycount return sub; // Found Exact match else { if (result!=-1) { if (!exact_match) result=-2; // AMBIGUOUS RESPONSE unless later exact match } else { if (!(flags & LMF_EXACT)) result=sub; } } } while (*lst) // Advance to end of cur entry. lst++; lst++; // Skip trailing zero sub++; } return result; } U0 UndefinedDefine(U8 *name) { ST_ERR_ST "Undefined Define: '%s'.\n",name; throw(EXCEPT_UNDEF_DEFINE,name); } U8 *Define(U8 *name) { CHashDefineStr *temph; if (temph=HashFind(name,Fs->hash_table,HTT_DEFINE_STR)) return temph->data; else if (name) UndefinedDefine(name); else return NULL; } U8 *DefineSub(I64 sub,U8 *name) { CHashDefineStr *temph; if (temph=HashFind(name,Fs->hash_table,HTT_DEFINE_STR)) { if (0<=subcnt) return temph->sub_lst[sub]; else return NULL; } else if (name) UndefinedDefine(name); else return NULL; } I64 DefineSubCnt(U8 *name) { CHashDefineStr *temph; if (temph=HashFind(name,Fs->hash_table,HTT_DEFINE_STR)) return temph->cnt; else if (name) UndefinedDefine(name); else return -1; } I64 DefineMatch(U8 *pattern,U8 *lst_name,I64 flags=0) { return LstMatch(pattern,Define(lst_name),flags); } U0 PutDefine(U8 *name) { "%s",Define(name); } U0 GetOutOfDollar() { CDoc *doc; if (IsRaw) { if (sys_raw_flags&RWF_IN_DOLLAR) '$$'; } else { if (fp_doc_put && (doc=(*fp_doc_put)(Fs)) && doc->flags&DOCF_IN_DOLLAR) '$$'; } } U0 NewLine(I64 cnt=1) { while (cnt-->0) '\n'; } U0 Spaces(I64 cnt=1) { while (cnt-->0) '' CH_SPACE; } U0 PutErr(U8 *st=NULL) { GetOutOfDollar; PutDefine("ST_ERR"); if (st) "%s\n",st; } U0 PutWarn(U8 *st=NULL) { GetOutOfDollar; PutDefine("ST_WARN"); if (st) "%s\n",st; } U0 PutDefineErr(U8 *st) { PutErr; PutDefine(st); } U0 PutDefineWarn(U8 *st) { PutWarn; PutDefine(st); } Bool YorN() { I64 ch; "(y or n)? "; while (TRUE) { ch=ToUpper(GetChar(,FALSE)); if (ch=='Y') { "$$PT$$YES$$FG$$\n"; return TRUE; } else if (ch=='N') { "$$PT$$NO$$FG$$\n"; return FALSE; } } } I64 PressAKey() { PutDefine("ST_PRESS_A_KEY"); return GetChar(,FALSE); } Bool AreYouSure() { PutDefine("ST_ARE_YOU_SURE"); return YorN; } CHashDefineStr *DefineLoad(U8 *name,U8 *st,Bool replace=FALSE) { CHashDefineStr *temph=CAlloc(sizeof(CHashDefineStr)); temph->type=HTT_DEFINE_STR; temph->str=StrNew(name); temph->data=StrNew(st); temph->cnt=-1; temph->caller=Caller; if (replace) HashReplace(temph,Fs->hash_table); else HashAdd(temph,Fs->hash_table); return temph; } CHashDefineStr *DefineLstLoad(U8 *name,U8 *st,Bool replace=FALSE) { //Not especially efficient but handy. I64 cnt=0; U8 *ptr,**lst; CHashDefineStr *temph=CAlloc(sizeof(CHashDefineStr)); temph->type=HTT_DEFINE_STR; temph->str=StrNew(name); ptr=st; while (*ptr) { while (*ptr++); cnt++; } temph->data=MAlloc(ptr+1-st); MemCpy(temph->data,st,ptr+1-st); temph->cnt=cnt; temph->caller=Caller; lst=temph->sub_lst=MAlloc(cnt*sizeof(U8 *)); ptr=st; while (*ptr) { if (*ptr!='@') *lst++=ptr; while (*ptr++); } if (replace) HashReplace(temph,Fs->hash_table); else HashAdd(temph,Fs->hash_table); return temph; } I64 StrOcc(U8 *src, I64 ch) { I64 i=0; if (!src) return 0; while (*src) if (*src++==ch) i++; return i; } I64 Spaces2Tabs(U8 *dst,U8 *src) { U8 *src2; I64 chged=0,space_cnt,space_cnt2,col=0; if (*src) while (TRUE) { src2=src; while (*src2==CH_SPACE) src2++; space_cnt=src2-src; while (col+space_cnt>=8) { space_cnt2=8-col; if (space_cnt2==1) *dst++=CH_SPACE; else { *dst++='\t'; chged+=space_cnt2-1; } space_cnt-=space_cnt2; col=0; } if (*src2=='\t') { if (space_cnt==1 && col==7) *dst++=CH_SPACE; else chged+=space_cnt; *dst++='\t'; col=0; } else { while (space_cnt--) { *dst++=CH_SPACE; if (++col==8) col=0; } if (*src2) { *dst++=*src2; if (++col==8) col=0; } else break; } src=++src2; } *dst=0; return chged; } U8 *Tabs2Spaces(U8 *src) { I64 i,j,l=StrLen(src)<<1+2,col=0; U8 ch,*dst=MAlloc(l),*temp; while (ch=*src++) { if (ch=='\t') { j=(col+8) & ~7; for (i=col;i=l-2) { temp=MAlloc(l<<1); MemCpy(temp,dst,i+1); Free(dst); l<<=1; dst=temp; } } col=j; } else { dst[col]=ch; if (col>=l-2) { temp=MAlloc(l<<1); MemCpy(temp,dst,col+1); Free(dst); l<<=1; dst=temp; } col++; } } dst[col]=0; return dst; } U8 *ScaleIndent(U8 *src,F64 indent_scale_factor) { I64 i,col=0; U8 ch,*dst,*dst2; while (ch=*src++) { if (ch=='\t') col=(col+8) & -0x8; else if (ch==CH_SPACE) col++; else break; } src--; col=Round(indent_scale_factor*col); dst=dst2=MAlloc(StrLen(src)+col/8+col&7+1); for (i=col/8;i>0;i--) *dst2++='\t'; for (i=col&7;i>0;i--) *dst2++=CH_SPACE; StrCpy(dst2,src); return dst; } U8 *StrUtil(U8 *_src,I64 flags) {//See $LK,"flags","MN:SUF_REM_SPACES"$ U8 *src=_src,*dst=_src; I64 ch; if (flags & SUF_REM_LEADING) while (Bt(white_space_bitmap,*src)) src++; while (ch=*src++) { if (Bt(white_space_bitmap,ch)) { if (!(flags & SUF_REM_SPACES)) { if (flags & SUF_SINGLE_SPACE) { *dst++ = CH_SPACE; while ((ch=*src++) && Bt(white_space_bitmap,ch)); src--; } else *dst++ = ch; } } else { if (!(flags & SUF_REM_CTRL_CHARS) || ch>=CH_SHIFT_SPACE) *dst++=ch; } } *dst=0; if (flags & SUF_CAP_UNDERSCORES) { src=_src; dst=_src; while (*src) { *dst++=ToUpper(*src++); while (*src && *src!='_') *dst++=*src++; if (*src=='_') src++; } *dst=0; } if (flags & SUF_REM_TRAILING) while (dst!=_src && (!*dst || Bt(white_space_bitmap,*dst))) *dst-- =0; if (flags & SUF_TO_UPPER) for (dst=_src;*dst;dst++) { ch=*dst; if ('a'<=ch<='z') *dst=ch-0x20; } if (flags & SUF_TO_LOWER) for (dst=_src;*dst;dst++) { ch=*dst; if ('A'<=ch<='Z') *dst=ch+0x20; } if (flags & SUF_SAFE_DOLLAR) for (dst=_src;*dst;dst++) { ch=*dst; if (!Bt(safe_dollar_chars_bitmap,*dst)) *dst='.'; } if (flags & SUF_S2T) Spaces2Tabs(_src,_src); return _src; } U8 *MStrUtil(U8 *src,I64 flags,F64 indent_scale_factor=0) //Return a $LK,"MAlloc","MN:MAlloc"$()ed result from StrUtil { U8 *dst=StrNew(src),*dst2,*temp; StrUtil(dst,flags); if (flags & SUF_T2S) { temp=Tabs2Spaces(dst); Free(dst); dst=temp; } if (flags & SUF_SCALE_INDENT) dst2=ScaleIndent(dst,indent_scale_factor); else dst2=StrNew(dst); //Shorten Free(dst); return dst2; } U8 *StrFirstOcc(U8 *src,U8 *marker) { U8 ch; while ((ch=*src++) && !StrOcc(marker,ch)); if (ch) return src-1; else return NULL; } U8 *StrFirstRem(U8 *src,U8 *marker,U8 *dst=NULL) { U8 *ptr=src,*result=dst,ch; if (dst) { while ((ch=*ptr++) && !StrOcc(marker,ch)) *dst++=ch; *dst=0; } else while ((ch=*ptr++) && !StrOcc(marker,ch)); if (ch) StrCpy(src,ptr); else *src=0; return result; } U8 *StrLastOcc(U8 *src,U8 *marker) { U8 ch,*result=NULL; while (ch=*src++) if (StrOcc(marker,ch)) result=src-1; return result; } U8 *StrLastRem(U8 *src,U8 *marker,U8 *dst=NULL) { U8 *ptr; if (ptr=StrLastOcc(src,marker)) { if (dst) StrCpy(dst,ptr+1); *ptr=0; } else { if (dst) StrCpy(dst,src); *src=0; } return dst; } U8 *StrFind(U8 *pattern,U8 *src,I64 flags=0) { Bool cont; U8 *saved_src=src; I64 plen=StrLen(pattern); do { cont=FALSE; if (flags & SFF_IGNORE_CASE) src=StrIMatch(pattern,src); else src=StrMatch(pattern,src); if (src && flags & SFF_WHOLE_LABELS_FRONT) { if (src!=saved_src) { if (Bt(alpha_numeric_bitmap,*(src-1))) { src++; if (*src) cont=TRUE; else src=NULL; } } } if (src && flags & SFF_WHOLE_LABELS_BACK) { if (Bt(alpha_numeric_bitmap,*(src+plen))) { src++; if (*src) cont=TRUE; else src=NULL; } } } while (cont); return src; } Bool WildMatch(U8 *pattern,U8 *wild) { I64 ch1,ch2; U8 *fall_back_src=NULL,*fall_back_wild=NULL; while (TRUE) { if (!(ch1=*pattern++)) { if (*wild && *wild!='*') return FALSE; else return TRUE; } else { if (!(ch2=*wild++)) return FALSE; else { if (ch2=='*') { fall_back_wild=wild-1; fall_back_src=pattern; if (!(ch2=*wild++)) return TRUE; while (ch2!=ch1) if (!(ch1=*pattern++)) return FALSE; } else if (ch2!='?' && ch1!=ch2) { if (fall_back_wild) { wild=fall_back_wild; pattern=fall_back_src; fall_back_wild=NULL; fall_back_src=NULL; } else return FALSE; } } } } } U8 *StrAdd(U8 *base,U8 *addition) //Concatinates a string onto another string. //Returns new string. //Dbls length when it grows. { U8 *result; I64 blen=StrLen(base),alen=StrLen(addition),bmem=MSize(base); if (blen+alen+1>bmem) { result=MAlloc(bmem<<1+alen+4); MemCpy(result,base,blen); StrCpy(result+blen,addition); Free(base); } else { result=base; StrCpy(result+blen,addition); } return result; } I64 A2I(U8 *st,I64 radix=10,U8 **_end_ptr=NULL) { //ASCII to Int Bool neg=FALSE; U8 ch; I64 result=0,k=0; if (!(2<=radix<=36)) return 0; while (Bt(white_space_bitmap,*st)) st++; if (*st=='-') { st++; neg=TRUE; } else if (*st=='+') st++; 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 (k==1 && !result) { if (ch=='X') { radix=16; goto ai_skip; } else if (ch=='B') { radix=2; goto ai_skip; } else if (ch=='O') { radix=8; goto ai_skip; } else if (ch=='D') { radix=10; goto ai_skip; } } if ('0'<=ch<='0'+radix-1) result=result*radix+ch-'0'; else break; } ai_skip: k++; } if (_end_ptr) *_end_ptr=st-1; if (neg) return -result; else return result; } U0 ScanFlags(U8 *f,U8 *lst,U8 *st) { I64 i; U8 *st2,*ptr; if (st) { st2=MAlloc(StrLen(st)+1); while (*st) { while (*st && *st!='+' && *st!='-') st++; if (*st=='+') { st++; if (*st) { ptr=st2; while (*st && *st!='+' && *st!='-' && *st!=CH_SPACE && *st!=CH_SHIFT_SPACE) *ptr++=*st++; *ptr=0; i=LstMatch(st2,lst); if (i>=0) LBts(f,i); else { Free(st2); throw(EXCEPT_FLAGS,1); } } } else if (*st=='-') { st++; if (*st) { ptr=st2; while (*st && *st!='+' && *st!='-' && *st!=CH_SPACE && *st!=CH_SHIFT_SPACE) *ptr++=*st++; *ptr=0; i=LstMatch(st2,lst); if (i>=0) LBtr(f,i); else { Free(st2); throw(EXCEPT_FLAGS,1); } } } } Free(st2); } } U8 *SPrintFlags(U8 *dst,U8 *lst,I64 flags) { I64 i; *dst=0; for (i=0;i<=63;i++) if (Bt(&flags,i)) { StrCat(dst,"+"); StrCat(dst,LstSub(i,lst)); } return dst; } U0 SPutChar(U8 **_dst,U8 ch,U8 **_buf) { I64 i; U8 *dst=*_dst,*buf; if (_buf) { buf=*_buf; i=dst-buf; if (i>=MSize(buf)) { buf=MAlloc(i<<1+1); MemCpy(buf,*_buf,i); dst=buf+i; *_buf=buf; } } *dst++=ch; *_dst=dst; } U0 OutStr(U8 *ptr,U8 **_buf,U8 **_dst, I64 len,Bool left_justify,Bool truncate_flag) { I64 i,j; if (!ptr) i=0; else i=StrLen(ptr); if (truncate_flag && i>len) i=len; if (left_justify) { for (j=0;j>6&7+'0',_buf); SPutChar(_dst,'$$'>>3&7+'0',_buf); SPutChar(_dst,'$$'&7+'0',_buf); } else { SPutChar(_dst,ch,_buf); SPutChar(_dst,ch,_buf); } break; case '\n': SPutChar(_dst,'\\',_buf); SPutChar(_dst,'n',_buf); break; case '\r': SPutChar(_dst,'\\',_buf); SPutChar(_dst,'r',_buf); break; case '\t': SPutChar(_dst,'\\',_buf); SPutChar(_dst,'t',_buf); break; case '"': case '\\': SPutChar(_dst,'\\',_buf); SPutChar(_dst,ch,_buf); break; default: if (CH_SHIFT_SPACE<=ch<=0x7F) { SPutChar(_dst,ch,_buf); } else { SPutChar(_dst,'\\',_buf); SPutChar(_dst,ch>>6&7+'0',_buf); SPutChar(_dst,ch>>3&7+'0',_buf); SPutChar(_dst,ch&7+'0',_buf); } } } SPutChar(_dst,0,_buf); return buf; } U8 *MPrintq(U8 *ptr) { U8 **_buf,*buf,**_dst,*dst; I64 i,ch,ch1; buf=MAlloc(128); _buf=&buf; dst=buf; _dst=&dst; if (ptr) while (ch=*ptr++) { ch1=*ptr; if (ch=='\\') switch (ch1) { case 'n': SPutChar(_dst,'\n',_buf); ptr++; break; case 'r': SPutChar(_dst,'\r',_buf); ptr++; break; case '"': SPutChar(_dst,'"',_buf); ptr++; break; case '\'': SPutChar(_dst,'\'',_buf); ptr++; break; case '\`': SPutChar(_dst,'\`',_buf); ptr++; break; case '\\': SPutChar(_dst,'\\',_buf); ptr++; break; case 't': SPutChar(_dst,'\t',_buf); ptr++; break; case 'x': case 'X': i=0; ptr++; while (TRUE) { ch1=ToUpper(*ptr++); if (Bt(hex_numeric_bitmap,ch1)) { if (ch1<='9') i=i<<4+ch1-'0'; else i=i<<4+ch1-'A'+10; } else break; } ptr--; SPutChar(_dst,i,_buf); break; case 'b': case 'B': i=0; ptr++; while (TRUE) { ch1=*ptr++; if ('0'<=ch1<='1') i=i<<1+ch1-'0'; else break; } ptr--; SPutChar(_dst,i,_buf); break; case 'o': case 'O': i=0; ptr++; goto sq_octal; case '0'...'7': i=ch1-'0'; ptr++; sq_octal: while (TRUE) { ch1=*ptr++; if ('0'<=ch1<='7') i=i<<3+ch1-'0'; else break; } ptr--; SPutChar(_dst,i,_buf); break; default: SPutChar(_dst,ch,_buf); } else if (ch=='$$' && ch1=='$$') { SPutChar(_dst,ch,_buf); ptr++; } else { SPutChar(_dst,ch,_buf); } } SPutChar(_dst,0,_buf); return buf; } U8 *sprint_pos_powers_lst= "kilo\0mega\0giga\0tera\0peta\0exa\0zetta\0yotta\0"; U8 *sprint_pos_powers_lets= " kMGTPEZY"; U8 *sprint_neg_powers_lst= "milli\0micro\0nano\0pico\0femto\0atto\0zepto\0yocto\0"; U8 *sprint_neg_powers_lets= " mænpfazy"; #define TEMP_BUF_LEN 256 #define SLOP 8 U8 *SPrintJoin(U8 *dst,U8 *src,I64 argc,I64 *argv) { //$LK,"Print Codes","FA:::/TempleOS/Doc/HolyC.TXT,Print_Codes"$ /* In float formatting, do not exceed 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. */ Bool pad_zero,left_justify,truncate_flag,neg,neg_e,comma_flag, dollar_flag,sub_fmt_question,has_sub_fmt,k_flag,has_decimal; I64 i,j,l,ch,k,k0,n,n0,len,dec_len,dec_len0,sub_fmt,comma_cnt,comma_fmt_cnt,cur_arg=0; U64 m; F64 d,d0,d1; U8 *ptr,**_buf,*buf,**_dst,*temp1,temp_buf[TEMP_BUF_LEN]; if (!src) throw(EXCEPT_SPRINT,0); if (dst) { _buf=NULL; buf=dst; } else { buf=MAlloc(128); _buf=&buf; dst=buf; } _dst=&dst; while (ch = *src++) { if (ch=='%') { if (*src=='-') { left_justify=TRUE; src++; } else left_justify=FALSE; if (*src=='0') { pad_zero=TRUE; src++; } else pad_zero=FALSE; len=0; while ('0'<=*src<='9') len=len*10+ *src++ -'0'; if (*src=='*') { src++; if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); len=argv[cur_arg++]; } dec_len=0; if (*src=='.') { src++; while ('0'<=*src<='9') dec_len=dec_len*10+ *src++ -'0'; if (*src=='*') { src++; if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); dec_len=argv[cur_arg++]; } has_decimal=TRUE; } else has_decimal=FALSE; dollar_flag=FALSE; comma_flag=FALSE; truncate_flag=FALSE; k_flag=FALSE; while (TRUE) { switch (*src) { case '$$': src++; dollar_flag=TRUE; break; case ',': src++; comma_flag=TRUE; break; case 't': src++; truncate_flag=TRUE; break; case 'k': src++; k_flag=TRUE; break; case 'l': //harmless src++; break; default: goto sp_in_sub_fmt; } } sp_in_sub_fmt: sub_fmt=0; if (*src!='h') has_sub_fmt=FALSE; else { src++; has_sub_fmt=TRUE; if (*src=='?') { src++; sub_fmt_question=TRUE; } else { sub_fmt_question=FALSE; if (*src=='*') { src++; if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); sub_fmt=argv[cur_arg++]; } else { if (*src=='-') { src++; neg=TRUE; } else neg=FALSE; while ('0'<=*src<='9') sub_fmt=sub_fmt*10+ *src++ -'0'; if (neg) sub_fmt=-sub_fmt; } } } neg=FALSE; k=0; switch (*src++) { case 's': if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); ptr=argv[cur_arg++]; OutStr(ptr,_buf,_dst,len,left_justify,truncate_flag); break; case 'S': if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); ptr=Define(argv[cur_arg++]); OutStr(ptr,_buf,_dst,len,left_justify,truncate_flag); break; case 'F': if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); ptr=TextFileRead(argv[cur_arg++]); OutStr(ptr,_buf,_dst,len,left_justify,truncate_flag); Free(ptr); break; case 'Q': if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); ptr=MPrintQ(argv[cur_arg++],dollar_flag); OutStr(ptr,_buf,_dst,len,left_justify,truncate_flag); Free(ptr); break; case 'q': if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); ptr=MPrintq(argv[cur_arg++]); OutStr(ptr,_buf,_dst,len,left_justify,truncate_flag); Free(ptr); break; case 'z': if (cur_arg+1>=argc) throw(EXCEPT_SPRINT,1); ptr=LstSub(argv[cur_arg],argv[cur_arg+1]); cur_arg=cur_arg+2; OutStr(ptr,_buf,_dst,len,left_justify,truncate_flag); break; case 'Z': if (cur_arg+1>=argc) throw(EXCEPT_SPRINT,1); ptr=DefineSub(argv[cur_arg],argv[cur_arg+1]); cur_arg=cur_arg+2; OutStr(ptr,_buf,_dst,len,left_justify,truncate_flag); break; case 'c': if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); temp_buf[0](I64)=argv[cur_arg++]; temp_buf[8] =0; OutStr(temp_buf,_buf,_dst,len,left_justify,truncate_flag); break; case 'C': if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); temp_buf[0](I64)=argv[cur_arg++]; temp_buf[8] =0; ptr=temp_buf; while (*ptr) { *ptr=ToUpper(*ptr); ptr++; } OutStr(temp_buf,_buf,_dst,len,left_justify,truncate_flag); break; case 'D': if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); temp1=MPrintDate(argv[cur_arg++],sub_fmt); OutStr(temp1,_buf,_dst,len,left_justify,truncate_flag); Free(temp1); break; case 'T': if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); temp1=MPrintTime(argv[cur_arg++],sub_fmt); OutStr(temp1,_buf,_dst,len,left_justify,truncate_flag); Free(temp1); break; case 'P': if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); if (truncate_flag) SPrintPSect(temp_buf,argv[cur_arg++],len); else SPrintPSect(temp_buf,argv[cur_arg++],0); OutStr(temp_buf,_buf,_dst,len,left_justify,truncate_flag); break; case 'd': if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); m=argv[cur_arg++]; if (m(I64)<0) { neg=TRUE; m=-m; } sp_out_dec: if (has_sub_fmt) { if (!len) len=12; d=m; goto sp_out_eng; } if (comma_flag) { comma_fmt_cnt=comma_cnt=3; do { temp_buf[k++]=ModU64(&m,10)+'0'; if (!m) break; if (!--comma_cnt) { temp_buf[k++]=','; comma_cnt=3; } } while (klen) k=len-i; if (k<0) k=0; if (pad_zero) { if (neg) SPutChar(_dst,'-',_buf); comma_cnt=(len-k-i+comma_fmt_cnt-comma_cnt+1)%(comma_fmt_cnt+1)+1; for (;i=len-k) break; } SPutChar(_dst,'0',_buf); } } else { for (;ilen) k=len-i; if (k<0) k=0; if (pad_zero) { if (neg) SPutChar(_dst,'-',_buf); for (;i=0;i--) SPutChar(_dst,temp_buf[i],_buf); break; case 'u': if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); m=argv[cur_arg++]; goto sp_out_dec; case 'f': if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); d=argv[cur_arg++](F64); if (d<0) { neg=TRUE; d=-d; } if (d==ì) { sp_out_inf: if (neg) i=1; else i=0; k=1; if (len<0) len=0; if (truncate_flag && k+i>len) k=len-i; if (k<0) k=0; for (;i17) { n+=i-17; d*=Pow10I64(i-n); } else { n=0; d*=Pow10I64(i); } i=dec_len; } else if (n>17) { n-=17; d*=Pow10I64(-n); } else n=0; m=Round(d); if (comma_flag) { comma_cnt=i&3; while (i-- && k2 && !comma_cnt--) { temp_buf[k++]=','; comma_cnt=2; if (!--i) break; } if (n) { n--; temp_buf[k++]='0'; } else temp_buf[k++]=ModU64(&m,10)+'0'; if (!i) break; } } else { while (i-- && k=argc) throw(EXCEPT_SPRINT,1); d=argv[cur_arg++](F64); if (d<0) { neg=TRUE; d=-d; } if (d==ì) goto sp_out_inf; if (d) n=Floor(Log10(d)); else n=0; sp_out_e: d/=Pow10I64(n); k0=k; for (l=0;l<2;l++) { n0=n; if (n<0) { n=-n; neg_e=TRUE; } else neg_e=FALSE; i=3; do temp_buf[k++]=ModU64(&n,10)+'0'; while (n && i--); if (neg_e) temp_buf[k++]='-'; temp_buf[k++]='e'; dec_len=len-k-neg-2; if (d) { d1=d+Pow10I64(-dec_len)/2; if (d1<1.0) { d*=10; n=n0-1; k=k0; } else if (d1>=10) { d/=10; n=n0+1; k=k0; } else break; } else break; } goto sp_out_f; case 'g': if (!len) len=12; truncate_flag=TRUE; if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); d=argv[cur_arg++](F64); if (d<0) { neg=TRUE; d=-d; } if (d==ì) goto sp_out_inf; if (d) n=Floor(Log10(d)); else n=0; if (n>=len-1-dec_len || n<-(dec_len-1)) goto sp_out_e; else goto sp_out_f; case 'n': if (!len) len=12; truncate_flag=TRUE; if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); d=argv[cur_arg++](F64); k_flag=TRUE; if (d<0) { neg=TRUE; d=-d; } sp_out_eng: //Engineering notation if (d==ì) goto sp_out_inf; if (k_flag) { if (d) n=FloorI64(Floor(Log10(d)),3); else n=0; d/=Pow10I64(n); } else { if (d) n=Floor(Ln(d)/Ln(1024)); else n=0; d/=1024`n; n*=3; } k0=k; dec_len0=dec_len; for (l=0;l<2;l++) { n0=n; d0=d; if (n<0) { n=-n; neg_e=TRUE; } else neg_e=FALSE; if (has_sub_fmt && -24<=n<=24) { if (sub_fmt_question) { if (neg_e) i=-n/3; else i=n/3; j=0; } else { if (neg_e) j=-n-sub_fmt; else j=n-sub_fmt; if (k_flag) d*=Pow10I64(j); else d*=1024`(j/3.0); i=sub_fmt/3; } if (i<0) temp_buf[k++]=sprint_neg_powers_lets[-i]; else if (i>0) temp_buf[k++]=sprint_pos_powers_lets[i]; else if (len!=0) temp_buf[k++]=CH_SPACE; if (!has_decimal) { dec_len=len-k-neg-2; if (j>0) { if (comma_flag) dec_len-=4*j/3; else dec_len-=j; } d1=d+Pow10I64(-dec_len+1)/2; if (d1>=10) { dec_len--; if (d1>=100) dec_len--; } } } else { i=3; do temp_buf[k++]=ModU64(&n,10)+'0'; while (n && i--); if (neg_e) temp_buf[k++]='-'; temp_buf[k++]='e'; if (!dec_len) { dec_len=len-k-neg-2; d1=d+Pow10I64(-dec_len+1)/2; if (d1>=10) { dec_len--; if (d1>=100) dec_len--; } } } if (comma_flag) { if (len && dec_len>0 && !(dec_len&3)) temp_buf[k++]=','; dec_len-=dec_len/4; } if (d) { d1=d+Pow10I64(-dec_len)/2; if (d1<1.0) { d=d0*1000; n=n0-3; k=k0; dec_len=dec_len0; } else if (d1>=1000) { d=d0/1000; n=n0+3; k=k0; dec_len=dec_len0; } else break; } else break; } goto sp_out_f; case 'X': if (cur_arg>=argc) throw(EXCEPT_SPRINT,1); m=argv[cur_arg++]; if (comma_flag) { comma_fmt_cnt=comma_cnt=4; do { temp_buf[k]= m&15 +'0'; if (temp_buf[k]>'9') temp_buf[k]+='A'-0x3A; k++; m>>=4; if (!m) break; if (!--comma_cnt) { temp_buf[k++]=','; comma_cnt=4; } } while (k'9') temp_buf[k]+='A'-0x3A; k++; m>>=4; } while (m && k=argc) throw(EXCEPT_SPRINT,1); m=argv[cur_arg++]; if (comma_flag) { comma_fmt_cnt=comma_cnt=4; do { temp_buf[k]= m&15 +'0'; if (temp_buf[k]>'9') temp_buf[k]+='a'-0x3A; k++; m>>=4; if (!m) break; if (!--comma_cnt) { temp_buf[k++]=','; comma_cnt=4; } } while (k'9') temp_buf[k]+='a'-0x3A; k++; m>>=4; } while (m && k=argc) throw(EXCEPT_SPRINT,1); m=argv[cur_arg++]; if (comma_flag) { comma_fmt_cnt=comma_cnt=4; do { temp_buf[k++]= m&1 +'0'; m>>=1; if (!m) break; if (!--comma_cnt) { temp_buf[k++]=','; comma_cnt=4; } } while (k>=1; } while (m && k=argc) throw(EXCEPT_SPRINT,1); m=argv[cur_arg++]; if (comma_flag) { comma_fmt_cnt=comma_cnt=3; do { temp_buf[k++]= m&7 +'0'; m>>=3; if (!m) break; if (!--comma_cnt) { temp_buf[k++]=','; comma_cnt=3; } } while (k>=3; } while (m && k=argc) throw(EXCEPT_SCAN,1); 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(EXCEPT_SCAN,1); dec_len=argv[cur_arg++]; } ch=*fmt++; } } buf=MAlloc(len+1); for (i=0;i=argc) throw(EXCEPT_SCAN,1); pptr=argv[cur_arg++]; StrCpy(*pptr,buf); break; case 'c': if (cur_arg>=argc) throw(EXCEPT_SCAN,1); ptr=argv[cur_arg++]; *ptr=*buf; break; case 'C': if (cur_arg>=argc) throw(EXCEPT_SCAN,1); ptr=argv[cur_arg++]; *ptr=ToUpper(*buf); break; case 'z': if (cur_arg+1>=argc) throw(EXCEPT_SCAN,1); i_ptr=argv[cur_arg++]; *i_ptr=LstMatch(buf,argv[cur_arg++]); break; case 'Z': if (cur_arg+1>=argc) throw(EXCEPT_SCAN,1); i_ptr=argv[cur_arg++]; *i_ptr=DefineMatch(buf,argv[cur_arg++]); break; case 'd': if (cur_arg>=argc) throw(EXCEPT_SCAN,1); i_ptr=argv[cur_arg++]; *i_ptr=A2I(buf); break; case 'X': if (cur_arg>=argc) throw(EXCEPT_SCAN,1); i_ptr=argv[cur_arg++]; *i_ptr=A2I(buf,16); break; case 'b': if (cur_arg>=argc) throw(EXCEPT_SCAN,1); i_ptr=argv[cur_arg++]; *i_ptr=A2I(buf,2); break; case 'e': case 'f': case 'g': case 'n': if (cur_arg>=argc) throw(EXCEPT_SCAN,1); d_ptr=argv[cur_arg++]; *d_ptr=A2F64(buf); break; case 'D': if (cur_arg>=argc) throw(EXCEPT_SCAN,1); 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); } U0 Print(U8 *fmt,...) {//$LK,"Print Extended Codes","FA:::/TempleOS/Doc/HolyC.TXT,Print_Codes"$ //See $LK,"SPrintJoin","MN:SPrintJoin"$() U8 *buf=SPrintJoin(NULL,fmt,argc,argv); PutS(buf); Free(buf); } U8 *MPrint(U8 *fmt,...) { //See $LK,"SPrintJoin","MN:SPrintJoin"$() U8 *result,*buf=SPrintJoin(NULL,fmt,argc,argv); result=StrNew(buf); Free(buf); return result; } U0 DefinePrint(U8 *name,U8 *src,...) { U8 *buf=SPrintJoin(NULL,src,argc,argv); DefineLoad(name,buf); Free(buf); } U0 PrintErr(U8 *fmt,...) { U8 *buf=SPrintJoin(NULL,fmt,argc,argv); PutErr; "%s",buf; Free(buf); } U0 PrintWarn(U8 *fmt,...) { U8 *buf=SPrintJoin(NULL,fmt,argc,argv); PutWarn; "%s",buf; Free(buf); } U0 Help() { if (IsInDbg) DbgHelp; else PopUp("Type(\"::/TempleOS/Doc/HelpIndex.TXT\");DocHome;View;"); }