Trivial Solutions
                    The LoseThos 64-bit PC Operating System
File:/LT/OSMain2/SPrintF2.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: OSMain2.SPZ
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 *sprintf_inf_msg="inf";

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

U8 *SPrintFJoin2(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,ch1,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;
          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);
          if (ptr=argv[cur_arg++])
            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_LINE_FEED:
                  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);
                  }
              }
            }
          break;
        case 'q':
          if (cur_arg>=argc)
            throw(EXCEPT_SPRINTF,1);
          if (ptr=argv[cur_arg++])
            while (ch=*ptr++) {
              ch1=*ptr;
              if (ch=='\\')
                switch (ch1) {
                  case 'n':
                    SPrintFPutChar(addr_dst,CH_LINE_FEED,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 sp_octal;
                  case '0'...'7':
                    i=ch1-'0';
                    ptr++;
sp_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);
            }
          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);
          SPrintFPutChar(addr_dst,argv[cur_arg++],addr_buf);
          break;
        case 'C':
          if (cur_arg>=argc)
            throw(EXCEPT_SPRINTF,1);
          SPrintFPutChar(addr_dst,ToUpper(argv[cur_arg++]),addr_buf);
          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-16);
          } else {
            do {
              temp_buf[k++]=ModU64(&m,10)+'0';
              if (!m) break;
            } while (k<TEMP_BUF_LEN-16);
          }

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=3;
            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,sprintf_inf_msg[i],addr_buf);
            break;
          }

sp_out_f:
          if (dec_len<0) dec_len=0;
          if (i=dec_len)
            dd*=Pow10I64(i);
          m=Round(dd);
          if (comma_flag) {
            comma_cnt=i%3;
            if (!comma_cnt)
              comma_cnt=3;
            while (i-- && k<TEMP_BUF_LEN-16) {
              temp_buf[k++]=ModU64(&m,10)+'0';
              if (!i) break;
              if (!--comma_cnt) {
                temp_buf[k++]=',';
                comma_cnt=3;
              }
            }
          } else {
            while (i-- && k<TEMP_BUF_LEN-16)
              temp_buf[k++]=ModU64(&m,10)+'0';
          }
          if (dec_len)
            temp_buf[k++]='.';
          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-16);
          } else {
            do {
              temp_buf[k++]=ModU64(&m,10)+'0';
              if (!m) break;
            } while (k<TEMP_BUF_LEN-16);
          }
          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%4))
                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-16) {
            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-16) {
            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-16) {
            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;
}

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=0,j=0,k=0;
  F64 d;
  BoolI8 neg=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;
  }
  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++;
  while (TRUE) {
    if (Bt(dec_numeric_bitmap,ch)) {
      j=j*10+ch-'0';
      k++;
    } else {
      d=i+j*Pow10I64(-k);
      if (ch=='e' || ch=='E') break;
      goto a2f_end;
    }
    ch=*src++;
  }
  ch=*src++;
  k=1;
  if (ch=='-') {
    k=-1;
    ch=*src++;
  }
  j=0;
  while (TRUE) {
    if (Bt(dec_numeric_bitmap,ch))
      j=j*10+ch-'0';
    else {
      d*=Pow10I64(j*k);
      goto a2f_end;
    }
    ch=*src++;
  }
a2f_end:
  if (_end_ptr) *_end_ptr=src-1;
  return neg ? -d:d;
}

/*
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;
}

U8 *GetFJoin2(U8 *src,U8 *fmt,I64i argc,I64i *argv)
//Pass ptr to data,
//For %s pass ptr to ptr (be careful because address
//of array is the same as array--create ptr to array and take address
{
  U8 ch,*buf,*ptr,**pptr;
  BoolI8 left_justify=FALSE;
  I64 cur_arg=0,i,j,k,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=0;
            for (k=0;k<len;k++)
              if (buf[k]!=CH_SPACE)
                *i_ptr=*i_ptr*10+(buf[k]-'0');
            break;
          case 'X':
            if (cur_arg>=argc)
              throw(EXCEPT_GETF,1);
            i_ptr=argv[cur_arg++];
            *i_ptr=0;
            for (k=0;k<len;k++)
              if (buf[k]!=CH_SPACE) {
                j=ToUpper(buf[k])-'0';
                if (j>9)  j=j-'A'+'9'+1;
                *i_ptr= *i_ptr<<4 +j;
              }
            break;
          case 'b':
            if (cur_arg>=argc)
              throw(EXCEPT_GETF,1);
            i_ptr=argv[cur_arg++];
            *i_ptr=0;
            for (k=0;k<len;k++)
              if (buf[k]!=CH_SPACE)
                *i_ptr=*i_ptr<<1+(buf[k]-'0');
            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;
}
Historical capture: 2010-11-18. Home | Power on LoseThos | Sources and changes