U8 *Tabs2Spaces(U8 *src)
{//MAlloc str with tabs to spaces.
  I64 ch,i,j,l=StrLen(src)<<1+2,col=0;
  U8 *dst=MAlloc(l),*tmp;
  while (ch=*src++) {
    if (ch=='\t') {
      j=(col+8) & ~7;
      for (i=col;i<j;i++) {
        dst[i]=CH_SPACE;
        if (i>=l-2) {
          tmp=MAlloc(l<<1);
          MemCpy(tmp,dst,i+1);
          Free(dst);
          l<<=1;
          dst=tmp;
        }
      }
      col=j;
    } else {
      dst[col]=ch;
      if (col>=l-2) {
        tmp=MAlloc(l<<1);
        MemCpy(tmp,dst,col+1);
        Free(dst);
        l<<=1;
        dst=tmp;
      }
      col++;
    }
  }
  dst[col]=0;
  return dst;
}

U8 *ScaleIndent(U8 *src,F64 indent_scale_factor)
{//MAlloced str.  8*0.25-->2 or 8*2.0-->16
  I64 ch,i,col=0;
  U8 *dst,*dst2;
  while (ch=*src++) {
    if (ch=='\t')
      col=(col+8) & -0x8;
    else if (ch==CH_SPACE)
      col++;
    else
      break;
  }
  src--;
  col=Round(indent_scale_factor*col);
  dst=dst2=MAlloc(StrLen(src)+col/8+col&7+1);
  for (i=col/8;i>0;i--)
    *dst2++='\t';
  for (i=col&7;i>0;i--)
    *dst2++=CH_SPACE;
  StrCpy(dst2,src);
  return dst;
}

U8 *MStrUtil(U8 *src,I64 flags,F64 indent_scale_factor=0)
{//MAlloc StrUtil().
  U8 *dst=StrNew(src),*dst2,*tmp;
  StrUtil(dst,flags);
  if (flags & SUF_T2S) {
    tmp=Tabs2Spaces(dst);
    Free(dst);
    dst=tmp;
  }
  if (flags & SUF_SCALE_INDENT)
    dst2=ScaleIndent(dst,indent_scale_factor);
  else
    dst2=StrNew(dst); //Shorten to just right size.
  Free(dst);
  return dst2;
}

U0 GetOutOfDollar()
{//If a $ has been printed, print another $ to exit mode.
  CDoc *doc;
  if (IsRaw) {
    if (text.raw_flags&RWF_IN_DOLLAR)
      '$';
  } else {
    if (fp_doc_put && (doc=(*fp_doc_put)(Fs)) && doc->flags&DOCF_IN_DOLLAR)
      '$';
  }
}

Bool YorN()
{//Wait for user to answer Y or N.
  I64 ch;
  "(y or n)? ";
  while (TRUE) {
    ch=ToUpper(GetChar(,FALSE));
    if (ch=='Y') {
      "$PT$YES$FG$\n";
      return TRUE;
    } else if (ch=='N') {
      "$PT$NO$FG$\n";
      return FALSE;
    }
  }
}

I64 PressAKey()
{//Print "Press a key" and wait for non-zero ASCII key.
  "$BK,1$PRESS A KEY$BK,0$\n";
  return GetChar(,FALSE);
}

Bool AreYouSure()
{//Print "Are you sure" and waits for Y or N.
  "ARE YOU SURE ";
  return YorN;
}

U0 Help()
{//Dbg help or master help index file.
  if (IsDbgMode)
    DbgHelp;
  else
    PopUp("Type(\"::/Doc/HelpIndex.DD\");DocTop;View;");
}

U0 ScanFlags(U8 *_dst_flags,U8 *lst,U8 *src)
{/*More than 64 flags. Flags passed by ref.

Examples:
ScanFlags(&fuf_flags,Define("ST_FILE_UTIL_FLAGS"),fu_flags);

I64 flags=0;
ScanFlags(&flags,"R\0L\0Dump\0Scan\0","+Dump-R"); //Sets Bit#2, Clears Bit#0.
*/
  I64 i;
  U8 *buf,*ptr;
  if (src) {
    buf=MAlloc(StrLen(src)+1);
    while (*src) {
      while (*src && *src!='+' && *src!='-')
        src++;
      if (*src=='+') {
        src++;
        if (*src) {
          ptr=buf;
          while (*src && *src!='+' && *src!='-' &&
                *src!=CH_SPACE && *src!=CH_SHIFT_SPACE)
            *ptr++=*src++;
          *ptr=0;
          i=LstMatch(buf,lst);
          if (i>=0)
            LBts(_dst_flags,i);
          else {
            Free(buf);
            throw('ScanFlag');
          }
        }
      } else if (*src=='-') {
        src++;
        if (*src) {
          ptr=buf;
          while (*src && *src!='+' && *src!='-' &&
                *src!=CH_SPACE && *src!=CH_SHIFT_SPACE)
            *ptr++=*src++;
          *ptr=0;
          i=LstMatch(buf,lst);
          if (i>=0)
            LBtr(_dst_flags,i);
          else {
            Free(buf);
            throw('ScanFlag');
          }
        }
      }
    }
    Free(buf);
  }
}

U8 *StrPrintFlags(U8 *dst,U8 *lst,I64 flags)
{//Only 64 flags. Flags passed by value.
  I64 i;
  *dst=0;
  while (flags) {
    i=Bsf(flags);
    Btr(&flags,i);
    CatPrint(dst,"+%z",i,lst);
  }
  return dst;
}