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); MemCopy(buf,*_buf,i); Free(*_buf); dst=buf+i; *_buf=buf; } } *dst++=ch; *_dst=dst; } U0 OutStr(U8 *ptr,U8 **_buf,U8 **_dst,I64 len,I64 flags) { I64 i,j; if (!ptr) i=0; else i=StrLen(ptr); if (flags&PRINTF_TRUNCATE && i>len) i=len; if (flags&PRINTF_LEFT_JUSTIFY) { for (j=0;j=CH_SPACE && ch!=0x7F) SPutChar(_dst,ch,_buf); else { StrPrint(buf2,"\\x%02X",ch); ptr2=buf2; while (*ptr2) SPutChar(_dst,*ptr2++,_buf); } } } SPutChar(_dst,0,_buf); return buf; } U8 *MPrintq(U8 *ptr,I64 flags) { U8 **_buf,*buf,**_dst,*dst; I64 i,j,ch,ch1; buf=MAlloc(STR_LEN); _buf=&buf; dst=buf; _dst=&dst; if (ptr) while (ch=*ptr++) { ch1=*ptr; switch (ch) { case '\\': switch (ch1) { start: case '0': SPutChar(_dst,0,_buf); break; case '\'': SPutChar(_dst,'\'',_buf); break; case '\`': SPutChar(_dst,'\`',_buf); break; case '"': SPutChar(_dst,'"',_buf); break; case '\\': SPutChar(_dst,'\\',_buf); break; case 'd': SPutChar(_dst,'$$',_buf); break; case 'n': SPutChar(_dst,'\n',_buf); break; case 'r': SPutChar(_dst,'\r',_buf); break; case 't': SPutChar(_dst,'\t',_buf); break; end: ptr++; break; case 'x': case 'X': i=0; ptr++; for (j=0;j<2;j++) { ch1=ToUpper(*ptr++); if (Bt(char_bmp_hex_numeric,ch1)) { if (ch1<='9') i=i<<4+ch1-'0'; else i=i<<4+ch1-'A'+10; } else { ptr--; break; } } SPutChar(_dst,i,_buf); break; default: SPutChar(_dst,ch,_buf); } break; case '$$': SPutChar(_dst,ch,_buf); if (ch1=='$$') ptr++; break; case '%': SPutChar(_dst,ch,_buf); if (flags&PRINTF_SLASH && ch1=='%') ptr++; break; default: SPutChar(_dst,ch,_buf); } } SPutChar(_dst,0,_buf); return buf; } U8 *sys_pos_pows_lets=" KMGTPEZY", *sys_neg_pows_lets=" mænpfazy", *sys_pos_pows_list="kilo\0mega\0giga\0tera\0peta\0exa\0zetta\0yotta\0", *sys_neg_pows_list="milli\0micro\0nano\0pico\0femto\0atto\0zepto\0yocto\0"; #define TMP_BUF_LEN 256 #define SLOP 8 U8 *StrPrintJoin(U8 *dst,U8 *format,I64 argc,I64 *argv) {/*$LK,"Print(\"\") Format Strings",A="FI:::/Doc/Print.DD"$ 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. */ I64 i,j,l,ch,k,k0,n,n0,len,dec_len,flags,old_flags, aux_format_num,comma_count,comma_format_count,cur_arg=0; U64 m; F64 d,d1; CDoc *doc; U8 *ptr,**_buf,*buf,**_dst,tmp_buf[TMP_BUF_LEN],tmp_buf2[TMP_BUF_LEN*2]; if (!format) throw('StrPrint'); if (dst) { _buf=NULL; buf=dst; } else { buf=MAlloc(STR_LEN); _buf=&buf; dst=buf; } _dst=&dst; while (ch = *format++) { if (ch=='%') { flags=0; if (*format=='-') { flags|=PRINTF_LEFT_JUSTIFY; format++; } if (*format=='0') { flags|=PRINTF_PAD_ZERO; format++; } len=0; while ('0'<=*format<='9') len=len*10+ *format++ -'0'; if (*format=='*') { format++; if (cur_arg>=argc) throw('StrPrint'); len=argv[cur_arg++]; } dec_len=0; if (*format=='.') { format++; while ('0'<=*format<='9') dec_len=dec_len*10+ *format++ -'0'; if (*format=='*') { format++; if (cur_arg>=argc) throw('StrPrint'); dec_len=argv[cur_arg++]; } flags|=PRINTF_DECIMAL; } aux_format_num=0; while (TRUE) { switch (*format) { start: case '$$': flags|=PRINTF_DOLLAR; break; case '/': flags|=PRINTF_SLASH; break; case ',': flags|=PRINTF_COMMA; break; case 't': flags|=PRINTF_TRUNCATE; break; case 'l': //harmless break; end: format++; break; case 'h': format++; flags|=PRINTF_AUX_FORMAT_NUM; if (*format=='?') { format++; flags|=PRINTF_QUESTION; } else { if (*format=='*') { format++; if (cur_arg>=argc) throw('StrPrint'); aux_format_num=argv[cur_arg++]; } else { if (*format=='-') { format++; flags|=PRINTF_NEG_AUX_FORMAT_NUM; } while ('0'<=*format<='9') aux_format_num=aux_format_num*10+ *format++ -'0'; if (flags&PRINTF_NEG_AUX_FORMAT_NUM) aux_format_num=-aux_format_num; } } break; default: goto sp_arg; } } sp_arg: k=0; switch (*format++) { start: case 'F': if (cur_arg>=argc) throw('StrPrint'); if (flags&PRINTF_DOLLAR) { doc=argv[cur_arg++]; old_flags=doc->flags; doc->flags|=DOCF_NO_CURSOR; ptr=DocSave(doc); doc->flags=old_flags; } else ptr=FileRead(argv[cur_arg++]); break; case 'Q': if (cur_arg>=argc) throw('StrPrint'); ptr=MPrintQ(argv[cur_arg++],flags); break; case 'q': if (cur_arg>=argc) throw('StrPrint'); ptr=MPrintq(argv[cur_arg++],flags); break; case 'D': if (cur_arg>=argc) throw('StrPrint'); ptr=MPrintDate(argv[cur_arg++]); break; case 'T': if (cur_arg>=argc) throw('StrPrint'); ptr=MPrintTime(argv[cur_arg++]); break; end: OutStr(ptr,_buf,_dst,len,flags); Free(ptr); break; start: case 's': if (cur_arg>=argc) throw('StrPrint'); ptr=argv[cur_arg++]; break; case 'S': if (cur_arg>=argc) throw('StrPrint'); ptr=Define(argv[cur_arg++]); break; case 'z': if (cur_arg+1>=argc) throw('StrPrint'); ptr=ListSub(argv[cur_arg],argv[cur_arg+1]); cur_arg=cur_arg+2; break; case 'Z': if (cur_arg+1>=argc) throw('StrPrint'); ptr=DefineSub(argv[cur_arg],argv[cur_arg+1]); cur_arg=cur_arg+2; break; end: OutStr(ptr,_buf,_dst,len,flags); break; start: case 'c': if (cur_arg>=argc) throw('StrPrint'); tmp_buf[0](I64)=argv[cur_arg++]; tmp_buf[8]=0; break; case 'C': if (cur_arg>=argc) throw('StrPrint'); tmp_buf[0](I64)=argv[cur_arg++]; tmp_buf[8]=0; ptr=tmp_buf; while (*ptr) { *ptr=ToUpper(*ptr); ptr++; } break; end: if (!(flags&PRINTF_AUX_FORMAT_NUM)) aux_format_num=1; while (aux_format_num-->0) OutStr(tmp_buf,_buf,_dst,len,flags); break; case 'p': if (cur_arg>=argc) throw('StrPrint'); StrPrintFunSeg(tmp_buf,argv[cur_arg++],len,flags); OutStr(tmp_buf,_buf,_dst,len,flags); break; case 'P': if (cur_arg>=argc) throw('StrPrint'); StrPrintFunSeg(tmp_buf,argv[cur_arg],len,flags); if (!IsRaw || !_buf) { StrPrint(tmp_buf2,"$$LK,\"%s\",A=\"AD:0x%X\"$$", tmp_buf,argv[cur_arg]); OutStr(tmp_buf2,_buf,_dst,len,flags); } else OutStr(tmp_buf,_buf,_dst,len,flags); cur_arg++; break; case 'd': if (cur_arg>=argc) throw('StrPrint'); m=argv[cur_arg++]; if (m(I64)<0) { flags|=PRINTF_NEG; m=-m; } sp_out_dec: if (flags&PRINTF_AUX_FORMAT_NUM) { if (!len) len=12; d=m; goto sp_out_eng; } if (flags&PRINTF_COMMA) { comma_format_count=comma_count=3; do { tmp_buf[k++]=ModU64(&m,10)+'0'; if (!m) break; if (!--comma_count) { tmp_buf[k++]=','; comma_count=3; } } while (klen) k=len-i; if (k<0) k=0; if (flags&PRINTF_PAD_ZERO) { if (flags&PRINTF_NEG) SPutChar(_dst,'-',_buf); comma_count=(len-k-i+comma_format_count-comma_count+1) %(comma_format_count+1)+1; for (;i=len-k) break; } SPutChar(_dst,'0',_buf); } } else { for (;ilen) k=len-i; if (k<0) k=0; if (flags&PRINTF_PAD_ZERO) { if (flags&PRINTF_NEG) SPutChar(_dst,'-',_buf); for (;i=0;i--) SPutChar(_dst,tmp_buf[i],_buf); break; case 'u': if (cur_arg>=argc) throw('StrPrint'); m=argv[cur_arg++]; goto sp_out_dec; case 'f': if (cur_arg>=argc) throw('StrPrint'); d=argv[cur_arg++](F64); if (d<0) { flags|=PRINTF_NEG; d=-d; } if (d==ì) { sp_out_inf: if (flags&PRINTF_NEG) i=1; else i=0; k=1; if (len<0) len=0; if (flags&PRINTF_TRUNCATE && 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 (flags&PRINTF_COMMA) { comma_count=i&3; while (i-- && k2 && !comma_count--) { tmp_buf[k++]=','; comma_count=2; if (!--i) break; } if (n) { n--; tmp_buf[k++]='0'; } else tmp_buf[k++]=ModU64(&m,10)+'0'; if (!i) break; } } else { while (i-- && k=argc) throw('StrPrint'); d=argv[cur_arg++](F64); if (d<0) { flags|=PRINTF_NEG; 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; flags|=PRINTF_NEG_E; } else flags&=~PRINTF_NEG_E; i=3; do tmp_buf[k++]=ModU64(&n,10)+'0'; while (n && i--); if (flags&PRINTF_NEG_E) tmp_buf[k++]='-'; tmp_buf[k++]='e'; dec_len=len-k-2; if (flags&PRINTF_NEG) dec_len--; 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; flags|=PRINTF_TRUNCATE; if (cur_arg>=argc) throw('StrPrint'); d=argv[cur_arg++](F64); if (d<0) { flags|=PRINTF_NEG; 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; flags|=PRINTF_TRUNCATE; if (cur_arg>=argc) throw('StrPrint'); d=argv[cur_arg++](F64); if (d<0) { flags|=PRINTF_NEG; d=-d; } sp_out_eng: //Engineering notation if (d==ì) goto sp_out_inf; if (d) n=FloorI64(Floor(Log10(d)),3); else n=0; d/=Pow10I64(n); if (n<0) { n=-n; flags|=PRINTF_NEG_E; } if (flags&PRINTF_AUX_FORMAT_NUM && -24<=n<=24) { if (flags&PRINTF_QUESTION) { if (flags&PRINTF_NEG_E) i=-n/3; else i=n/3; j=0; } else { if (flags&PRINTF_NEG_E) j=-n-aux_format_num; else j=n-aux_format_num; d*=Pow10I64(j); i=aux_format_num/3; } if (i<0) tmp_buf[k++]=sys_neg_pows_lets[-i]; else if (i>0) tmp_buf[k++]=sys_pos_pows_lets[i]; else if (len!=0) tmp_buf[k++]=CH_SPACE; if (!(flags&PRINTF_DECIMAL)) { dec_len=len-k-2; if (flags&PRINTF_NEG) dec_len--; if (j>0) { if (flags&PRINTF_COMMA) 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 tmp_buf[k++]=ModU64(&n,10)+'0'; while (n && i--); if (flags&PRINTF_NEG_E) tmp_buf[k++]='-'; tmp_buf[k++]='e'; if (!dec_len) { dec_len=len-k-2; if (flags&PRINTF_NEG) dec_len--; d1=d+Pow10I64(-dec_len+1)/2; if (d1>=10) { dec_len--; if (d1>=100) dec_len--; } } } if (flags&PRINTF_COMMA) { if (len && dec_len>0 && !(dec_len&3)) tmp_buf[k++]=','; dec_len-=dec_len/4; } goto sp_out_f; case 'X': if (cur_arg>=argc) throw('StrPrint'); m=argv[cur_arg++]; if (flags&PRINTF_COMMA) { comma_format_count=comma_count=4; do { tmp_buf[k]= m&15 +'0'; if (tmp_buf[k]>'9') tmp_buf[k]+='A'-0x3A; k++; m>>=4; if (!m) break; if (!--comma_count) { tmp_buf[k++]=','; comma_count=4; } } while (k'9') tmp_buf[k]+='A'-0x3A; k++; m>>=4; } while (m && k=argc) throw('StrPrint'); m=argv[cur_arg++]; if (flags&PRINTF_COMMA) { comma_format_count=comma_count=4; do { tmp_buf[k]= m&15 +'0'; if (tmp_buf[k]>'9') tmp_buf[k]+='a'-0x3A; k++; m>>=4; if (!m) break; if (!--comma_count) { tmp_buf[k++]=','; comma_count=4; } } while (k'9') tmp_buf[k]+='a'-0x3A; k++; m>>=4; } while (m && k=argc) throw('StrPrint'); m=argv[cur_arg++]; if (flags&PRINTF_COMMA) { comma_format_count=comma_count=4; do { tmp_buf[k++]= m&1 +'0'; m>>=1; if (!m) break; if (!--comma_count) { tmp_buf[k++]=','; comma_count=4; } } while (k>=1; } while (m && k