function printf(fstring)
{ var pad = function(str,ch,len)
    { var ps='';
      for(var i=0; i<Math.abs(len); i++) ps+=ch;
      return len>0?str+ps:ps+str;
    }
  var processFlags = function(flags,width,rs,arg)
    { var pn = function(flags,arg,rs)
        { if(arg>=0)
            { if(flags.indexOf(' ')>=0) rs = ' ' + rs;
              else if(flags.indexOf('+')>=0) rs = '+' + rs;
            }
          else
              rs = '-' + rs;
          return rs;
        }
      var iWidth = parseInt(width,10);
      if(width.charAt(0) == '0')
        { var ec=0;
          if(flags.indexOf(' ')>=0 || flags.indexOf('+')>=0) ec++;
          if(rs.length<(iWidth-ec)) rs = pad(rs,'0',rs.length-(iWidth-ec));
          return pn(flags,arg,rs);
        }
      rs = pn(flags,arg,rs);
      if(rs.length<iWidth)
        { if(flags.indexOf('-')<0) rs = pad(rs,' ',rs.length-iWidth);
          else rs = pad(rs,' ',iWidth - rs.length);
        }    
      return rs;
    }
  var converters = new Array();
  converters['c'] = function(flags,width,precision,arg)
    { if(typeof(arg) == 'number') return String.fromCharCode(arg);
      if(typeof(arg) == 'string') return arg.charAt(0);
      return '';
    }
  converters['d'] = function(flags,width,precision,arg)
    { return converters['i'](flags,width,precision,arg); 
    }
  converters['u'] = function(flags,width,precision,arg)
    { return converters['i'](flags,width,precision,Math.abs(arg)); 
    }
  converters['i'] =  function(flags,width,precision,arg)
    { var iPrecision=parseInt(precision);
      var rs = ((Math.abs(arg)).toString().split('.'))[0];
      if(rs.length<iPrecision) rs=pad(rs,' ',iPrecision - rs.length);
      return processFlags(flags,width,rs,arg); 
    }
  converters['E'] = function(flags,width,precision,arg) 
    { return (converters['e'](flags,width,precision,arg)).toUpperCase();
    }
  converters['e'] =  function(flags,width,precision,arg)
    { iPrecision = parseInt(precision);
      if(isNaN(iPrecision)) iPrecision = 6;
      rs = (Math.abs(arg)).toExponential(iPrecision);
      if(rs.indexOf('.')<0 && flags.indexOf('#')>=0) rs = rs.replace(/^(.*)(e.*)$/,'$1.$2');
      return processFlags(flags,width,rs,arg);        
    }
  converters['f'] = function(flags,width,precision,arg)
    { iPrecision = parseInt(precision);
      if(isNaN(iPrecision)) iPrecision = 6;
      rs = (Math.abs(arg)).toFixed(iPrecision);
      if(rs.indexOf('.')<0 && flags.indexOf('#')>=0) rs = rs + '.';
      return processFlags(flags,width,rs,arg);
    }
  converters['G'] = function(flags,width,precision,arg)
    { return (converters['g'](flags,width,precision,arg)).toUpperCase();
    }
  converters['g'] = function(flags,width,precision,arg)
    { iPrecision = parseInt(precision);
      absArg = Math.abs(arg);
      rse = absArg.toExponential();
      rsf = absArg.toFixed(6);
      if(!isNaN(iPrecision))
        { rsep = absArg.toExponential(iPrecision);
          rse = rsep.length < rse.length ? rsep : rse;
          rsfp = absArg.toFixed(iPrecision);
          rsf = rsfp.length < rsf.length ? rsfp : rsf;
        }
      if(rse.indexOf('.')<0 && flags.indexOf('#')>=0) rse = rse.replace(/^(.*)(e.*)$/,'$1.$2');
      if(rsf.indexOf('.')<0 && flags.indexOf('#')>=0) rsf = rsf + '.';
      rs = rse.length<rsf.length ? rse : rsf;
      return processFlags(flags,width,rs,arg);        
    }  
  converters['o'] = function(flags,width,precision,arg)
    { var iPrecision=parseInt(precision);
      var rs = Math.round(Math.abs(arg)).toString(8);
      if(rs.length<iPrecision) rs=pad(rs,' ',iPrecision - rs.length);
      if(flags.indexOf('#')>=0) rs='0'+rs;
      return processFlags(flags,width,rs,arg); 
    }
  converters['X'] = function(flags,width,precision,arg)
    { return (converters['x'](flags,width,precision,arg)).toUpperCase();
    }
  converters['x'] = function(flags,width,precision,arg)
    { var iPrecision=parseInt(precision);
      arg = Math.abs(arg);
      var rs = Math.round(arg).toString(16);
      if(rs.length<iPrecision) rs=pad(rs,' ',iPrecision - rs.length);
      if(flags.indexOf('#')>=0) rs='0x'+rs;
      return processFlags(flags,width,rs,arg); 
    }
  converters['s'] = function(flags,width,precision,arg)
    { var iPrecision=parseInt(precision);
      var rs = arg;
      if(rs.length > iPrecision) rs = rs.substring(0,iPrecision);
      return processFlags(flags,width,rs,0);
    }
  farr = fstring.split('%');
  retstr = farr[0];
  fpRE = /^([-+ #]*)(\d*)\.?(\d*)([cdieEfFgGosuxX])(.*)$/;
  for(var i=1; i<farr.length; i++)
    { fps=fpRE.exec(farr[i]);
      if(!fps) continue;
      if(arguments[i]!=null) retstr+=converters[fps[4]](fps[1],fps[2],fps[3],arguments[i]);
      retstr += fps[5];
    }
  return retstr;
}
