Trivial Solutions The LoseThos 64-bit PC Operating System File:/LT/OSMain/Str1a.CPZ This, and all LoseThos files, are public domain. Do whatever you like. God is watching; God is just; God is never out-done in generosity. He talks! LoseThos code compiles with the 64-bit LoseThos compiler/assembler I wrote. Boot the LoseThos CD and you can compile it. Not in Kansas anymore! Click here for preliminary compiler information you need. Project: OSMain U8 hex_digits[16]="0123456789ABCDEF"; U8 *Bin2Hex(U8 *dst,U64 n;U64 width) { U8 *result=dst+width; dst=result; while (width--) { *--dst=hex_digits[n&15]; n>>=4; } return result; } U0 PutHex(U64 n,U64 width) { U8 buf[17]; if (width>16) width=16; *Bin2Hex(buf,n,width)=0; "" 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 OR AL,AL JNZ @@05 MOV RDI,RSI DEC RDI MOV RSI,U64 SF_ARG2[RBP] @@10: LODSB STOSB OR AL,AL JNZ @@10 POP RDI POP RSI LEAVE RET1 16 // ************************************ _STRCPY:: ENTER 0 PUSH RSI PUSH RDI MOV RSI,U64 SF_ARG2[RBP] MOV RDI,U64 SF_ARG1[RBP] @@05: LODSB STOSB OR AL,AL JNZ @@05 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 OR 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 OR 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] OR 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: OR RCX,RCX JZ @@25 DEC RCX LODSB OR 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] OR 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: OR RCX,RCX JZ @@35 DEC RCX LODSB OR 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 // ************************************ _STRSTR:: ENTER 0 PUSH RSI PUSH RDI MOV RSI,U64 SF_ARG1[RBP] MOV RDI,U64 SF_ARG2[RBP] MOV DL,U8 [RDI] OR DL,DL JZ @@20 JMP @@10 @@05: INC RSI @@10: LODSB OR AL,AL JZ @@25 CMP AL,DL JNE @@10 DEC RSI MOV RCX,1 @@15: MOV AL,U8 [RDI+RCX] OR 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 // ************************************ _STRISTR:: ENTER 0 PUSH RSI PUSH RDI MOV RSI,U64 SF_ARG1[RBP] MOV RDI,U64 SF_ARG2[RBP] MOV AL,U8 [RDI] CALL TO_UPPER MOV DL,AL OR DL,DL JZ @@20 JMP @@10 @@05: INC RSI @@10: LODSB CALL TO_UPPER OR AL,AL JZ @@25 CMP AL,DL JNE @@10 DEC RSI MOV RCX,1 @@15: MOV AL,U8 [RDI+RCX] CALL TO_UPPER OR 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 } LTextern _STRCMP I64 StrCmp(U8 *st1,U8 *st2); LTextern _STRICMP I64 StrICmp(U8 *st1,U8 *st2); LTextern _STRNCMP I64 StrNCmp(U8 *st1,U8 *st2,U64 n); LTextern _STRNICMP I64 StrNICmp(U8 *st1,U8 *st2,U64 n); LTextern _STRSTR U8 *StrStr(U8 *st,U8 *pattern); LTextern _STRISTR U8 *StrIStr(U8 *st,U8 *pattern); LTextern _STRCPY U0 StrCpy(U8 *dest,U8 *src); LTextern _STRCAT U0 StrCat(U8 *dest,U8 *src); /* These bitmaps go to 0-511 so that Lex() can use them with Token Codes. */ 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 *ListEntryPoint(I64 entry_num, U8 *lst) {//Point to list entry. //Not especially efficient but handy. Use an array of U8*'s for efficiency. while (*lst && entry_num>0) { while (*lst) // Advance to end of cur entry. lst++; lst++; // Skip trailing zero entry_num--; if (*lst=='@') { // Check for '@' alias list entry entry_num++; lst++; } } if (entry_num) return NULL; else return lst; } I64 ListEntryMatch(U8 *src, U8 *lst,I64 flags=0,I64 *ambiguity_overkill_ptr=NULL) // RETURNS: -2 if Ambiguous, -1 if not found, else entry_num { //Not especially efficient but handy. Use hash tables for efficiency. I64 n,entry_num=0,result=-1,unutilized_src; U8 *s; BoolI8 exact_match=FALSE; n=StrLen(src); if (ambiguity_overkill_ptr) *ambiguity_overkill_ptr=n; while (*lst) { if (*lst=='@') { /* Check for '@' alias list entry*/ entry_num--; lst++; } s=src; if (flags & LEF_IGNORE_CASE) while (*s && ToUpper(*s) == ToUpper(*lst)) { s++; lst++; } else while (*s && *s==*lst) { s++; lst++; } unutilized_src=n-(s-src); if (!*s) { // Did we reach end of src if (!*lst) { // Did we reach end of list entrycount if (!ambiguity_overkill_ptr) return entry_num; // Found Exact match result=entry_num; exact_match=TRUE; } else { if (result!=-1) { if (ambiguity_overkill_ptr) *ambiguity_overkill_ptr=0; if (!exact_match) result=-2; // AMBIGUOUS RESPONSE unless later exact match } else { if (!(flags & LEF_EXACT)) result=entry_num; } } } else { if (ambiguity_overkill_ptr && *ambiguity_overkill_ptr>unutilized_src-1) *ambiguity_overkill_ptr=unutilized_src-1; } while (*lst) // Advance to end of cur entry. lst++; lst++; // Skip trailing zero entry_num++; } if (ambiguity_overkill_ptr && result==-1) *ambiguity_overkill_ptr=0; return result; } U0 UndefinedDefine(U8 *name) { ST_ERR_ST "Undefined Define: '"; "" name; "'.\n"; throw(EXCEPT_UNDEF_DEFINE,name); } U8 *Define(U8 *name) { DefineStrHashEntry *temph=HashFind(name,Fs->hash_table,HTT_DEFINE_STR); if (temph) return temph->data; else UndefinedDefine(name); } U8 *DefineSub(U64 sub,U8 *name) { DefineStrHashEntry *temph=HashFind(name,Fs->hash_table,HTT_DEFINE_STR); if (temph) return ListEntryPoint(sub,temph->data); else UndefinedDefine(name); } I64 DefineSubCnt(U8 *name) { DefineStrHashEntry *temph=HashFind(name,Fs->hash_table,HTT_DEFINE_STR); if (temph) return temph->cnt; else UndefinedDefine(name); } I64 DefineMatch(U8 *src,U8 *lst_name, U64 flags=0,I64 *ambiguity_overkill_ptr=NULL) { return ListEntryMatch(src,Define(lst_name), flags,ambiguity_overkill_ptr); } U0 PutDefine(U8 *name) { "" Define(name); } U0 GetOutOfDollar() { Ltf *l; if (IsRaw) { if (sys_raw_dc_flags&RDCF_IN_DOLLAR) '$'; } else { if (fp_ltf_cur && (l=(*fp_ltf_cur)(Fs)) && l->flags<FF_IN_DOLLAR) '$'; } } U0 NewLine(I64 cnt=1) { while (cnt-->0) '' CH_NEW_LINE; } U0 Spaces(I64 cnt=1) { while (cnt-->0) '' CH_SPACE; } U0 PutErr(U8 *st=NULL) { GetOutOfDollar; PutDefine("ST_ERR"); if (st) { "" st; NewLine; } } U0 PutWarn(U8 *st=NULL) { GetOutOfDollar; PutDefine("ST_WARN"); if (st) { "" st; NewLine; } } U0 PutDefineErr(U8 *st) { PutErr; PutDefine(st); } U0 PutDefineWarn(U8 *st) { PutWarn; PutDefine(st); } BoolI64 YorN() { U64 ch; "(y or n)? "; while (TRUE) { ch=ToUpper(GetChar(NULL,FALSE)); if (ch=='Y') { "$FU$YES$FG$\n"; return TRUE; } else if (ch=='N') { "$FU$NO$FG$\n"; return FALSE; } } } BoolI64 PressAKey() { U64 ch; PutDefine("ST_PRESS_A_KEY"); ch=GetChar(NULL,FALSE); if (ch==CH_SHIFT_ESC || ch==CH_ESC) return FALSE; else return TRUE; } BoolI64 ExitAllApplications() { U64 ch; PutDefine("ST_EXIT_ALL_APPLICATIONS"); PutDefine("ST_PRESS_A_KEY"); ch=GetChar(NULL,FALSE); if (ch==CH_SHIFT_ESC || ch==CH_ESC) return FALSE; else return TRUE; } BoolI64 AreYouSure() { PutDefine("ST_ARE_YOU_SURE"); return YorN; } DefineStrHashEntry *DefineLoad(U8 *name,U8 *st,BoolI8 replace=FALSE) { DefineStrHashEntry *temph=CAlloc(sizeof(DefineStrHashEntry)); 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; } DefineStrHashEntry *DefineListLoad(U8 *name,U8 *st,BoolI8 replace=FALSE) { //Not especially efficient but handy. I64 cnt=0; U8 *ptr; DefineStrHashEntry *temph=CAlloc(sizeof(DefineStrHashEntry)); 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; if (replace) HashReplace(temph,Fs->hash_table); else HashAdd(temph,Fs->hash_table); return temph; } I64 StrOcc(U8 *src, U64 ch) { I64 i=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++=CH_TAB; chged+=space_cnt2-1; } space_cnt-=space_cnt2; col=0; } if (*src2==CH_TAB) { if (space_cnt==1 && col==7) *dst++=CH_SPACE; else chged+=space_cnt; *dst++=CH_TAB; 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==CH_TAB) { j=(col+8) & ~7; for (i=col;i<j;i++) { dst[i]=CH_SPACE; if (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==CH_TAB) 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++=CH_TAB; for (i=col&7;i>0;i--) *dst2++=CH_SPACE; StrCpy(dst2,src); return dst; } U8 *StrUtil(U8 *_src,I64 flags) {//See flags U8 *src=_src,*dst=_src; U64 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,U64 flags,F64 indent_scale_factor=0) //Return a 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 *SearchStr(U8 *src,U8 *pattern,U64 flags=0) { BoolI8 cont; U8 *src2; U8 *saved_src=src; I64 plen=StrLen(pattern); do { cont=FALSE; if (flags & SRF_IGNORE_CASE) src=StrIStr(src,pattern); else src=StrStr(src,pattern); if (src && flags & SRF_WHOLE_LABELS) { src2=src+plen; if (Bt(alpha_numeric_bitmap,*src2)) { src++; if (*src) cont=TRUE; else src=NULL; } else { if (src!=saved_src) { src2=src-1; if (Bt(alpha_numeric_bitmap,*src2)) { src++; if (*src) cont=TRUE; else src=NULL; } } } } } while (cont); return src; } BoolI64 WildCardMatch(U8 *wild,U8 *src) { U64 ch1,ch2; U8 *fall_back_src,*fall_back_wild=NULL; while (TRUE) { if (!(ch1=*src++)) { if (*wild) return FALSE; else return TRUE; } else { if (!(ch2=*wild++)) return FALSE; else { if (ch2=='*') { fall_back_wild=wild-1; fall_back_src=src; if (!(ch2=*wild++)) return TRUE; while (ch2!=ch1) if (!(ch1=*src++)) return FALSE; } else if (ch2!='?' && ch1!=ch2) { if (fall_back_wild) { wild=fall_back_wild; src=fall_back_src; fall_back_wild=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); I64 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 BoolI8 neg=FALSE; U8 ch; I64 result=0,k=0; if (radix<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; return neg ? -result:result; } U0 GetFFlags(U0 *f,U8 *list,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=ListEntryMatch(st2,list); if (i>=0) LBts(f,i); } } else if (*st=='-') { st++; if (*st) { ptr=st2; while (*st && *st!='+' && *st!='-' && *st!=CH_SPACE && *st!=CH_SHIFT_SPACE) *ptr++=*st++; *ptr=0; i=ListEntryMatch(st2,list); if (i>=0) LBtr(f,i); } } } Free(st2); } } U8 *SPrintFFlags(U8 *dst,U8 *list,U64 flags) { I64 i; *dst=0; for (i=0;i<=63;i++) if (Bt(&flags,i)) { StrCat(dst,"+"); StrCat(dst,ListEntryPoint(i,list)); } return dst; } U0 SPrintFPutChar(U8 **addr_dst,U8 ch,U8 **addr_buf) { I64 i; U8 *dst=*addr_dst,*buf; if (addr_buf) { buf=*addr_buf; i=dst-buf; if (i>=MSize(buf)) { buf=MAlloc(i<<1+1); MemCpy(buf,*addr_buf,i); dst=buf+i; *addr_buf=buf; } } *dst++=ch; *addr_dst=dst; } U0 OutStr(U8 *ptr,U8 **addr_buf,U8 *addr_dst, I64 len,BoolI8 left_justify,BoolI8 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<i;j++) SPrintFPutChar(addr_dst,*ptr++,addr_buf); for (j=0;j<len-i;j++) SPrintFPutChar(addr_dst,CH_SPACE,addr_buf); } else { for (j=0;j<len-i;j++) SPrintFPutChar(addr_dst,CH_SPACE,addr_buf); for (j=len-i;j<len;j++) SPrintFPutChar(addr_dst,*ptr++,addr_buf); } } U8 *MSPrintFTime(LTDate dt,U64 sub_fmt) { LTDateStruct d; if (sub_fmt<NUM_TIME_FMTS) sub_fmt=time_fmt_map[sub_fmt]; switch (sub_fmt) { case 1: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d:%02d",d.hour,d.min); case 2: LTDate2LTDateStruct(&d,dt+local_time_offset); if (d.hour>=12) return MSPrintF("%02d:%02d:%02d pm",d.hour-12,d.min,d.sec); else return MSPrintF("%02d:%02d:%02d am",d.hour,d.min,d.sec); case 3: LTDate2LTDateStruct(&d,dt+local_time_offset); if (d.hour>=12) return MSPrintF("%02d:%02d pm",d.hour-12,d.min); else return MSPrintF("%02d:%02d am",d.hour,d.min); case 4: LTDate2LTDateStruct(&d,dt+local_time_offset); if (d.hour>=12) return MSPrintF("%02d:%02d:%02dp",d.hour-12,d.min,d.sec); else return MSPrintF("%02d:%02d:%02da",d.hour,d.min,d.sec); case 5: LTDate2LTDateStruct(&d,dt+local_time_offset); if (d.hour>=12) return MSPrintF("%02d:%02dp",d.hour-12,d.min); else return MSPrintF("%02d:%02da",d.hour,d.min); case 6: LTDate2LTDateStruct(&d,dt); return MSPrintF("%dh %02dm",d.hour+dt.date*24,d.min); case 7: LTDate2LTDateStruct(&d,dt); return MSPrintF("%dh %02dm %02ds",d.hour+dt.date*24,d.min,d.sec); case 8: LTDate2LTDateStruct(&d,dt); return MSPrintF("%dd %02dh %02dm",dt.date,d.hour,d.min); case 9: LTDate2LTDateStruct(&d,dt); return MSPrintF("%dd %02dh %02dm %02ds",dt.date,d.hour,d.min,d.sec); case 10: LTDate2LTDateStruct(&d,dt); return MSPrintF("%dd %02dh %02dm %02d.%02ds",dt.date,d.hour,d.min,d.sec,d.sec100); case 11: LTDate2LTDateStruct(&d,dt); return MSPrintF("%dh %02dm %02d.%02ds",d.hour+dt.date*24,d.min,d.sec,d.sec100); case 12: LTDate2LTDateStruct(&d,dt); return MSPrintF("%d.%02d",60*((dt.date*24+d.hour)*60+d.min)+d.sec,d.sec100); case 13: LTDate2LTDateStruct(&d,dt); return MSPrintF("%02d:%02d.%02d",60*(dt.date*24+d.hour)+d.min,d.sec,d.sec100); case 14: LTDate2LTDateStruct(&d,dt); return MSPrintF("%02d:%02d:%02d.%02d",dt.date*24+d.hour,d.min,d.sec,d.sec100); case 15: LTDate2LTDateStruct(&d,dt); return MSPrintF("%dd %02dh %02dm %02d.%04ds",dt.date,d.hour,d.min,d.sec,100*d.sec100+d.sec10000); case 16: LTDate2LTDateStruct(&d,dt); return MSPrintF("%dh %02dm %02d.%04ds",d.hour+dt.date*24,d.min,d.sec,100*d.sec100+d.sec10000); case 17: LTDate2LTDateStruct(&d,dt); return MSPrintF("%d.%04d",60*((dt.date*24+d.hour)*60+d.min)+d.sec,100*d.sec100+d.sec10000); case 18: LTDate2LTDateStruct(&d,dt); return MSPrintF("%02d:%02d.%04d",60*(dt.date*24+d.hour)+d.min,d.sec,100*d.sec100+d.sec10000); case 19: LTDate2LTDateStruct(&d,dt); return MSPrintF("%02d:%02d:%02d.%04d",dt.date*24+d.hour,d.min,d.sec,100*d.sec100+d.sec10000); case 20: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d",d.hour); case 21: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d",d.min); case 22: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d",d.sec); default: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d:%02d:%02d",d.hour,d.min,d.sec); } } U8 *MSPrintFDate(LTDate dt,U64 sub_fmt) { LTDateStruct d; if (sub_fmt<NUM_DATE_FMTS) sub_fmt=date_fmt_map[sub_fmt]; switch (sub_fmt) { case 1: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d/%02d",d.mon,d.day_of_mon); case 2: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ %02d/%02d",d.day_of_week,"ST_DAYS_OF_WEEK", d.mon,d.day_of_mon); case 3: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ %02d/%02d/%02d",d.day_of_week,"ST_DAYS_OF_WEEK", d.mon,d.day_of_mon,d.year%100); case 4: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d/%02d/%d",d.mon,d.day_of_mon,d.year); case 5: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ %02d/%02d/%d",d.day_of_week,"ST_DAYS_OF_WEEK", d.mon,d.day_of_mon,d.year); case 6: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ %02d",d.mon-1,"ST_MONTHS",d.day_of_mon); case 7: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ, %3tZ %02d",d.day_of_week,"ST_DAYS_OF_WEEK", d.mon-1,"ST_MONTHS",d.day_of_mon); case 8: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ %02d,%04d",d.mon-1,"ST_MONTHS",d.day_of_mon,d.year); case 9: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ, %3tZ %02d,%d",d.day_of_week,"ST_DAYS_OF_WEEK", d.mon-1,"ST_MONTHS",d.day_of_mon,d.year); case 10: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%Z %d",d.mon-1,"ST_MONTHS",d.day_of_mon); case 11: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%Z, %Z %d",d.day_of_week,"ST_DAYS_OF_WEEK", d.mon-1,"ST_MONTHS",d.day_of_mon); case 12: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%Z %d,%d",d.mon-1,"ST_MONTHS",d.day_of_mon,d.year); case 13: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%Z, %Z %d,%d",d.day_of_week,"ST_DAYS_OF_WEEK", d.mon-1,"ST_MONTHS",d.day_of_mon,d.year); case 14: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d/%02d/%02d",d.day_of_mon,d.mon,d.year%100); case 15: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d/%02d",d.day_of_mon,d.mon); case 16: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ %02d/%02d",d.day_of_week,"ST_DAYS_OF_WEEK", d.day_of_mon,d.mon); case 17: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ %02d/%02d/%02d",d.day_of_week,"ST_DAYS_OF_WEEK", d.day_of_mon,d.mon,d.year%100); case 18: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d/%02d/%d",d.day_of_mon,d.mon,d.year); case 19: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ %02d/%02d/%d",d.day_of_week,"ST_DAYS_OF_WEEK", d.day_of_mon,d.mon,d.year); case 20: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d %3tZ",d.day_of_mon,d.mon-1,"ST_MONTHS"); case 21: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ, %02d %3tZ",d.day_of_week,"ST_DAYS_OF_WEEK", d.day_of_mon,d.mon-1,"ST_MONTHS"); case 22: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d %3tZ,%04d",d.day_of_mon,d.mon-1,"ST_MONTHS",d.year); case 23: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ, %02d %3tZ,%d",d.day_of_week,"ST_DAYS_OF_WEEK", d.day_of_mon,d.mon-1,"ST_MONTHS",d.year); case 24: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%d %Z",d.day_of_mon,d.mon-1,"ST_MONTHS"); case 25: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%Z, %d %Z",d.day_of_week,"ST_DAYS_OF_WEEK", d.day_of_mon,d.mon-1,"ST_MONTHS"); case 26: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%d %Z,%d",d.day_of_mon,d.mon-1,"ST_MONTHS",d.year); case 27: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%Z, %d %Z,%d",d.day_of_week,"ST_DAYS_OF_WEEK", d.day_of_mon,d.mon-1,"ST_MONTHS",d.year); case 28: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d/%02d/%02d",d.year%100,d.mon,d.day_of_mon); case 29: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%d/%02d/%02d",d.year,d.mon,d.day_of_mon); case 30: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d%02d%02d",d.year%100,d.mon,d.day_of_mon); case 31: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%d%02d%02d",d.year,d.mon,d.day_of_mon); case 32: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d%02d%02d",d.mon,d.day_of_mon,d.year%100); case 33: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d%02d%d",d.mon,d.day_of_mon,d.year); case 34: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ",d.day_of_week,"ST_DAYS_OF_WEEK"); case 35: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%Z",d.day_of_week,"ST_DAYS_OF_WEEK"); case 36: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ",d.mon-1,"ST_MONTHS"); case 37: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%Z",d.mon-1,"ST_MONTHS"); case 38: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%d %3tZ",d.year,d.mon-1,"ST_MONTHS"); case 39: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%d %Z",d.year,d.mon-1,"ST_MONTHS"); case 40: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d %3tZ",d.year%100,d.mon-1,"ST_MONTHS"); case 41: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d %Z",d.year%100,d.mon-1,"ST_MONTHS"); case 42: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ %d",d.mon-1,"ST_MONTHS",d.year); case 43: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%Z %d",d.mon-1,"ST_MONTHS",d.year); case 44: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%3tZ %02d",d.mon-1,"ST_MONTHS",d.year%100); case 45: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%Z %02d",d.mon-1,"ST_MONTHS",d.year%100); case 46: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d",d.year%100); case 47: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%d",d.year); case 48: return MSPrintF("%d days",dt.date); case 49: return MSPrintF("%d mons",ToI64(dt/(LT_YEAR_DAYS/12))>>32); case 50: return MSPrintF("%d years",ToI64(dt/LT_YEAR_DAYS)>>32); case 51: return MSPrintF("%d",dt.date); case 52: return MSPrintF("%d",ToI64(dt/(LT_YEAR_DAYS/12))>>32); case 53: return MSPrintF("%d",ToI64(dt/LT_YEAR_DAYS)>>32); case 54: return MSPrintF("%0.1f",dt/ToF64(MAX_U32+1)); case 55: return MSPrintF("%0.1f",dt/ToF64(MAX_U32+1)/(LT_YEAR_DAYS/12)); case 56: return MSPrintF("%0.1f",dt/ToF64(MAX_U32+1)/LT_YEAR_DAYS); default: LTDate2LTDateStruct(&d,dt+local_time_offset); return MSPrintF("%02d/%02d/%02d",d.mon,d.day_of_mon,d.year%100); } } U8 *MSPrintFQ(U8 *ptr,BoolI8 dollar_flag) { U8 **addr_buf,*buf,*addr_dst,*dst; I64 ch; buf=MAlloc(128); addr_buf=&buf; dst=buf; addr_dst=&dst; if (ptr) while (ch=*ptr++) { switch (ch) { case '$': if (dollar_flag) { SPrintFPutChar(addr_dst,'\\',addr_buf); SPrintFPutChar(addr_dst,'$'>>6&7+'0',addr_buf); SPrintFPutChar(addr_dst,'$'>>3&7+'0',addr_buf); SPrintFPutChar(addr_dst,'$'&7+'0',addr_buf); } else { SPrintFPutChar(addr_dst,ch,addr_buf); SPrintFPutChar(addr_dst,ch,addr_buf); } break; case CH_NEW_LINE: SPrintFPutChar(addr_dst,'\\',addr_buf); SPrintFPutChar(addr_dst,'n',addr_buf); break; case CH_CR: SPrintFPutChar(addr_dst,'\\',addr_buf); SPrintFPutChar(addr_dst,'r',addr_buf); break; case CH_TAB: SPrintFPutChar(addr_dst,'\\',addr_buf); SPrintFPutChar(addr_dst,'t',addr_buf); break; case '"': case '\\': SPrintFPutChar(addr_dst,'\\',addr_buf); SPrintFPutChar(addr_dst,ch,addr_buf); break; default: if (CH_SHIFT_SPACE<=ch<=0x7F) { SPrintFPutChar(addr_dst,ch,addr_buf); } else { SPrintFPutChar(addr_dst,'\\',addr_buf); SPrintFPutChar(addr_dst,ch>>6&7+'0',addr_buf); SPrintFPutChar(addr_dst,ch>>3&7+'0',addr_buf); SPrintFPutChar(addr_dst,ch&7+'0',addr_buf); } } } SPrintFPutChar(addr_dst,0,addr_buf); return buf; } U8 *MSPrintFq(U8 *ptr) { U8 **addr_buf,*buf,*addr_dst,*dst; I64 i,ch,ch1; buf=MAlloc(128); addr_buf=&buf; dst=buf; addr_dst=&dst; if (ptr) while (ch=*ptr++) { ch1=*ptr; if (ch=='\\') switch (ch1) { case 'n': SPrintFPutChar(addr_dst,CH_NEW_LINE,addr_buf); ptr++; break; case 'r': SPrintFPutChar(addr_dst,CH_CR,addr_buf); ptr++; break; case '"': SPrintFPutChar(addr_dst,'"',addr_buf); ptr++; break; case '\'': SPrintFPutChar(addr_dst,'\'',addr_buf); ptr++; break; case '\`': SPrintFPutChar(addr_dst,'\`',addr_buf); ptr++; break; case '\\': SPrintFPutChar(addr_dst,'\\',addr_buf); ptr++; break; case 't': SPrintFPutChar(addr_dst,CH_TAB,addr_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--; SPrintFPutChar(addr_dst,i,addr_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--; SPrintFPutChar(addr_dst,i,addr_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--; SPrintFPutChar(addr_dst,i,addr_buf); break; default: SPrintFPutChar(addr_dst,ch,addr_buf); } else if (ch=='$' && ch1=='$') { SPrintFPutChar(addr_dst,ch,addr_buf); ptr++; } else { SPrintFPutChar(addr_dst,ch,addr_buf); } } SPrintFPutChar(addr_dst,0,addr_buf); return buf; } U8 *sprintf_pos_powers_list= "kilo\0mega\0giga\0tera\0peta\0exa\0zetta\0yotta\0"; U8 *sprintf_pos_powers_lets= " kMGTPEZY"; U8 *sprintf_neg_powers_list= "milli\0micro\0nano\0pico\0femto\0atto\0zepto\0yocto\0"; U8 *sprintf_neg_powers_lets= " munpfazy"; #define TEMP_BUF_LEN 256 #define SLOP 8 U8 *SPrintFJoin(U8 *dst,U8 *src,I64 argc,I64 *argv) { //printF 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. */ U8 *ptr,**addr_buf,*buf,*addr_dst,*temp1; BoolI8 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; U64 m,cur_arg=0; F64 dd,dd0,dd1; U8 temp_buf[TEMP_BUF_LEN]; if (!src) throw(EXCEPT_SPRINTF,0); if (dst) { addr_buf=NULL; buf=dst; } else { buf=MAlloc(128); addr_buf=&buf; dst=buf; } addr_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_SPRINTF,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_SPRINTF,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_SPRINTF,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_SPRINTF,1); ptr=argv[cur_arg++]; OutStr(ptr,addr_buf,addr_dst,len,left_justify,truncate_flag); break; case 'S': if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); ptr=Define(argv[cur_arg++]); OutStr(ptr,addr_buf,addr_dst,len,left_justify,truncate_flag); break; case 'F': if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); ptr=TextFileRead(argv[cur_arg++]); OutStr(ptr,addr_buf,addr_dst,len,left_justify,truncate_flag); Free(ptr); break; case 'Q': if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); ptr=MSPrintFQ(argv[cur_arg++],dollar_flag); OutStr(ptr,addr_buf,addr_dst,len,left_justify,truncate_flag); Free(ptr); break; case 'q': if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); ptr=MSPrintFq(argv[cur_arg++]); OutStr(ptr,addr_buf,addr_dst,len,left_justify,truncate_flag); Free(ptr); break; case 'z': if (cur_arg+1>=argc) throw(EXCEPT_SPRINTF,1); ptr=ListEntryPoint(argv[cur_arg],argv[cur_arg+1]); cur_arg=cur_arg+2; OutStr(ptr,addr_buf,addr_dst,len,left_justify,truncate_flag); break; case 'Z': if (cur_arg+1>=argc) throw(EXCEPT_SPRINTF,1); ptr=DefineSub(argv[cur_arg],argv[cur_arg+1]); cur_arg=cur_arg+2; OutStr(ptr,addr_buf,addr_dst,len,left_justify,truncate_flag); break; case 'c': if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); temp_buf[0]><(U64)=argv[cur_arg++]; temp_buf[8] =0; OutStr(temp_buf,addr_buf,addr_dst,len,left_justify,truncate_flag); break; case 'C': if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); temp_buf[0]><(U64)=argv[cur_arg++]; temp_buf[8] =0; ptr=temp_buf; while (*ptr) { *ptr=ToUpper(*ptr); ptr++; } OutStr(temp_buf,addr_buf,addr_dst,len,left_justify,truncate_flag); break; case 'D': if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); temp1=MSPrintFDate(argv[cur_arg++],sub_fmt); OutStr(temp1,addr_buf,addr_dst,len,left_justify,truncate_flag); Free(temp1); break; case 'T': if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); temp1=MSPrintFTime(argv[cur_arg++],sub_fmt); OutStr(temp1,addr_buf,addr_dst,len,left_justify,truncate_flag); Free(temp1); break; case 'P': if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); if (truncate_flag) SPrintFPSect(temp_buf,argv[cur_arg++],len); else SPrintFPSect(temp_buf,argv[cur_arg++],0); OutStr(temp_buf,addr_buf,addr_dst,len,left_justify,truncate_flag); break; case 'd': if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); m=argv[cur_arg++]; if (m><(I64)<0) { neg=TRUE; m=-m; } sp_out_dec: if (has_sub_fmt) { if (!len) len=12; dd=m; goto sp_out_eng; } if (comma_flag) { comma_cnt=3; do { temp_buf[k++]=ModU64(&m,10)+'0'; if (!m) break; if (!--comma_cnt) { temp_buf[k++]=','; comma_cnt=3; } } while (k<TEMP_BUF_LEN-SLOP); } else { do { temp_buf[k++]=ModU64(&m,10)+'0'; if (!m) break; } while (k<TEMP_BUF_LEN-SLOP); } sp_out_num: if (neg) i=1; else i=0; if (len<0) len=0; if (truncate_flag && k+i>len) k=len-i; if (k<0) k=0; if (pad_zero) { if (neg) SPrintFPutChar(addr_dst,'-',addr_buf); for (;i<len-k;i++) SPrintFPutChar(addr_dst,'0',addr_buf); } else { for (;i<len-k;i++) SPrintFPutChar(addr_dst,CH_SPACE,addr_buf); if (neg) SPrintFPutChar(addr_dst,'-',addr_buf); } for (i=k-1;i>=0;i--) SPrintFPutChar(addr_dst,temp_buf[i],addr_buf); break; case 'u': if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); m=argv[cur_arg++]; goto sp_out_dec; case 'f': if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); dd=argv[cur_arg++]><(F64); if (dd<0) { neg=TRUE; dd=-dd; } if (dd==inf) { 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 (;i<len-k;i++) SPrintFPutChar(addr_dst,CH_SPACE,addr_buf); if (neg) SPrintFPutChar(addr_dst,'-',addr_buf); for (i=0;i<k;i++) SPrintFPutChar(addr_dst,'inf',addr_buf); break; } sp_out_f: if (dec_len<0) dec_len=0; n=Log10(dd); if (i=dec_len) { if (comma_flag) i=i-i/4; if (n+i>17) { n+=i-17; dd*=Pow10I64(i-n); } else { n=0; dd*=Pow10I64(i); } i=dec_len; } else if (n>17) { n-=17; dd*=Pow10I64(-n); } else n=0; m=Round(dd); if (comma_flag) { comma_cnt=i&3; while (i-- && k<TEMP_BUF_LEN-SLOP) { if (i>2 && !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<TEMP_BUF_LEN-SLOP) { if (n) { n--; temp_buf[k++]='0'; } else temp_buf[k++]=ModU64(&m,10)+'0'; } } if (dec_len) temp_buf[k++]='.'; if (comma_flag) { comma_cnt=3; do { if (n) { n--; temp_buf[k++]='0'; } else temp_buf[k++]=ModU64(&m,10)+'0'; if (!m) break; if (!--comma_cnt) { temp_buf[k++]=','; comma_cnt=3; } } while (k<TEMP_BUF_LEN-SLOP); } else { do { if (n) { n--; temp_buf[k++]='0'; } else temp_buf[k++]=ModU64(&m,10)+'0'; if (!m) break; } while (k<TEMP_BUF_LEN-SLOP); } goto sp_out_num; case 'e': if (!len) len=12; truncate_flag=TRUE; if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); dd=argv[cur_arg++]><(F64); if (dd<0) { neg=TRUE; dd=-dd; } if (dd==inf) goto sp_out_inf; if (dd) n=Floor(Log10(dd)); else n=0; sp_out_e: dd/=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 (dd) { dd1=dd+Pow10I64(-dec_len)/2; if (dd1<1.0) { dd*=10; n=n0-1; k=k0; } else if (dd1>=10) { dd/=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_SPRINTF,1); dd=argv[cur_arg++]><(F64); if (dd<0) { neg=TRUE; dd=-dd; } if (dd==inf) goto sp_out_inf; if (dd) n=Floor(Log10(dd)); 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_SPRINTF,1); dd=argv[cur_arg++]><(F64); k_flag=TRUE; if (dd<0) { neg=TRUE; dd=-dd; } sp_out_eng: //Engineering notation if (dd==inf) goto sp_out_inf; if (k_flag) { if (dd) n=FloorI64(Floor(Log10(dd)),3); else n=0; dd/=Pow10I64(n); } else { if (dd) n=Floor(Ln(dd)/Ln(1024)); else n=0; dd/=1024`n; n*=3; } k0=k; dec_len0=dec_len; for (l=0;l<2;l++) { n0=n; dd0=dd; 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) dd*=Pow10I64(j); else dd*=1024`(j/3.0); i=sub_fmt/3; } if (i<0) temp_buf[k++]=sprintf_neg_powers_lets[-i]; else if (i>0) temp_buf[k++]=sprintf_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; } dd1=dd+Pow10I64(-dec_len+1)/2; if (dd1>=10) { dec_len--; if (dd1>=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; dd1=dd+Pow10I64(-dec_len+1)/2; if (dd1>=10) { dec_len--; if (dd1>=100) dec_len--; } } } if (comma_flag) { if (len && dec_len>0 && !(dec_len&3)) temp_buf[k++]=','; dec_len-=dec_len/4; } if (dd) { dd1=dd+Pow10I64(-dec_len)/2; if (dd1<1.0) { dd=dd0*1000; n=n0-3; k=k0; dec_len=dec_len0; } else if (dd1>=1000) { dd=dd0/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_SPRINTF,1); m=argv[cur_arg++]; while ((!k || m) && k<TEMP_BUF_LEN-SLOP) { temp_buf[k]= m&15 +'0'; if (temp_buf[k]>'9') temp_buf[k]+='A'-0x3A; k++; m>>=4; } goto sp_out_num; case 'x': if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); m=argv[cur_arg++]; while ((!k || m) && k<TEMP_BUF_LEN-SLOP) { temp_buf[k]= m&15 +'0'; if (temp_buf[k]>'9') temp_buf[k]+='a'-0x3A; k++; m>>=4; } goto sp_out_num; case 'b': if (cur_arg>=argc) throw(EXCEPT_SPRINTF,1); m=argv[cur_arg++]; while ((!k || m) && k<TEMP_BUF_LEN-SLOP) { temp_buf[k++]= m&1 +'0'; m>>=1; } goto sp_out_num; case '%': SPrintFPutChar(addr_dst,'%',addr_buf); break; } } else SPrintFPutChar(addr_dst,ch,addr_buf); } SPrintFPutChar(addr_dst,0,addr_buf); return buf; } U8 *SPrintF(U8 *dst,U8 *fmt,...) { //See SPrintFJoin() return SPrintFJoin(dst,fmt,argc,argv); } /* A2LTDate() 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. */ LTDate A2LTDate(U8 *_src) //ASCII date to LTDate { LTDate result=0; LTDateStruct d,d1; U8 *src=MStrUtil(_src,SUF_REM_SPACES|SUF_TO_UPPER), *v=StrNew(src), *p1=src; BoolI8 start_mon=FALSE,end_mon=FALSE; BoolI8 start_year=FALSE,end_year=FALSE; MemSet(&d,0,sizeof(LTDateStruct)); MemSet(&d1,0,sizeof(LTDateStruct)); 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=A2I(p1,10,&p1); result+=GetCurTimeLTDate+local_time_offset; } else { StrFirstRem(p1,"/",v); //Put mon into v d.mon=A2I(v); if (StrOcc(p1,'/')) { StrFirstRem(p1,"/",v); //Put day into v leaving year in p1 d.day_of_mon=A2I(v); d.year=A2I(p1,10,&p1); if (d.year<100) //if not 4 digit year d.year+=2000; } else { d.day_of_mon=A2I(p1,10,&p1); LTDate2LTDateStruct(&d1,GetCurTimeLTDate+local_time_offset); d.year=d1.year; } result=LTDateStruct2LTDate(&d); } 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+=A2I(p1); Free(src); Free(v); return result-local_time_offset; } 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. */ { U8 ch=*src++; I64 i,j,k; F64 d; BoolI8 neg=FALSE,neg_e=FALSE; while (Bt(white_space_bitmap,ch)) ch=*src++; if (ch=='-') { neg=TRUE; ch=*src++; } if (!StrNCmp(src-1,"inf",3)) { d=inf; src+=3; goto a2f_end; } if (*src=='inf') { d=inf; src++; goto a2f_end; } i=0; while (TRUE) { if (Bt(dec_numeric_bitmap,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(dec_numeric_bitmap,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(dec_numeric_bitmap,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; return neg ? -d:d; } U8 *GetFJoin(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; BoolI8 left_justify=FALSE; I64 cur_arg=0,i,len,*i_ptr,dec_len; F64 *d_ptr; if (!fmt) throw(EXCEPT_GETF,0); 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(EXCEPT_GETF,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_GETF,1); dec_len=argv[cur_arg++]; } ch=*fmt++; } } buf=MAlloc(len+1); for (i=0;i<len;i++) buf[i]=*src++; buf[i]=0; switch (ch) { case 's': if (cur_arg>=argc) throw(EXCEPT_GETF,1); pptr=argv[cur_arg++]; StrCpy(*pptr,buf); break; case 'c': if (cur_arg>=argc) throw(EXCEPT_GETF,1); ptr=argv[cur_arg++]; *ptr=*buf; break; case 'C': if (cur_arg>=argc) throw(EXCEPT_GETF,1); ptr=argv[cur_arg++]; *ptr=ToUpper(*buf); break; case 'z': if (cur_arg+1>=argc) throw(EXCEPT_GETF,1); i_ptr=argv[cur_arg++]; *i_ptr=ListEntryMatch(buf,argv[cur_arg++]); break; case 'Z': if (cur_arg+1>=argc) throw(EXCEPT_GETF,1); i_ptr=argv[cur_arg++]; *i_ptr=DefineMatch(buf,argv[cur_arg++]); break; case 'd': if (cur_arg>=argc) throw(EXCEPT_GETF,1); i_ptr=argv[cur_arg++]; *i_ptr=A2I(buf); break; case 'X': if (cur_arg>=argc) throw(EXCEPT_GETF,1); i_ptr=argv[cur_arg++]; *i_ptr=A2I(buf,16); break; case 'b': if (cur_arg>=argc) throw(EXCEPT_GETF,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_GETF,1); d_ptr=argv[cur_arg++]; *d_ptr=A2F64(buf); break; case 'D': if (cur_arg>=argc) throw(EXCEPT_GETF,1); i_ptr=argv[cur_arg++]; *i_ptr=A2LTDate(buf); break; } Free(buf); } } else src++; } return src; } U8 *GetF(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 GetFJoin(src,fmt,argc,argv); } U0 PrintF(U8 *fmt,...) {//PrintF Extended Codes //See SPrintFJoin() U8 *buf=SPrintFJoin(NULL,fmt,argc,argv); "" buf; Free(buf); } U8 *MSPrintF(U8 *fmt,...) { //See SPrintFJoin() U8 *result,*buf=SPrintFJoin(NULL,fmt,argc,argv); result=StrNew(buf); Free(buf); return result; } U0 DefinePrintF(U8 *name,U8 *src,...) { U8 *buf=SPrintFJoin(NULL,src,argc,argv); DefineLoad(name,buf); Free(buf); } U0 PrintFErr(U8 *fmt,...) { U8 *buf=SPrintFJoin(NULL,fmt,argc,argv); PutErr; "" buf; Free(buf); } U0 PrintFWarn(U8 *fmt,...) { U8 *buf=SPrintFJoin(NULL,fmt,argc,argv); PutWarn; "" buf; Free(buf); }