Permalink
Jan 14, 2015
Jan 14, 2015
Jan 1, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Feb 9, 2016
Jan 14, 2015
Jan 14, 2015
Feb 9, 2016
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Feb 9, 2016
Dec 3, 2015
Dec 3, 2015
Jan 6, 2016
Jan 1, 2015
Jan 1, 2015
Jan 30, 2016
Oct 12, 2016
Newer
100644
1712 lines (1546 sloc)
55.1 KB
13
function normalize_start_end($){
14
if($.start===null||$.start===_b_.None){$.start = 0}
15
else if($.start<0){$.start += $.self.length; $.start=Math.max(0, $.start)}
16
if($.end===null||$.end===_b_.None){$.end = $.self.length}
17
else if($.end<0){$.end += $.self.length; $.end=Math.max(0, $.end)}
18
19
if(!isinstance($.start,_b_.int)||!isinstance($.end,_b_.int)){
20
throw _b_.TypeError(
21
"slice indices must be integers or None or have an __index__ method")}
22
23
}
24
25
function reverse(s){
26
// Reverse a string
27
return s.split('').reverse().join('')
28
}
29
30
function check_str(obj){
31
if(!_b_.isinstance(obj,str)){throw _b_.TypeError("can't convert '"+
32
$B.get_class(obj).__name__+"' object to str implicitely")}
35
$StringDict.__add__ = function(self,other){
36
if(!(typeof other==="string")){
37
try{return getattr(other,'__radd__')(self)}
38
catch(err){throw _b_.TypeError(
39
"Can't convert "+$B.get_class(other).__name__+" to str implicitely")}
40
}
41
return self+other
42
}
43
44
$StringDict.__contains__ = function(self,item){
45
if(!(typeof item==="string")){throw _b_.TypeError(
46
"'in <string>' requires string as left operand, not "+item.__class__)}
47
var nbcar = item.length
48
if(nbcar==0) return true // a string contains the empty string
49
if(self.length==0) return nbcar==0
51
if(self.substr(i,nbcar)==item) return true
52
}
53
return false
54
}
55
56
$StringDict.__delitem__ = function(){
57
throw _b_.TypeError("'str' object doesn't support item deletion")
58
}
59
60
// __dir__must be assigned explicitely because attribute resolution for builtin
61
// classes doesn't use __mro__
62
$StringDict.__dir__ = $ObjectDict.__dir__
63
64
$StringDict.__eq__ = function(self,other){
65
if(other===undefined){ // compare object "self" to class "str"
66
return self===str
67
}
68
if (_b_.isinstance(other, _b_.str)) {
69
return other.valueOf() == self.valueOf()
70
}
74
function preformat(self, fmt){
75
if(fmt.empty){return _b_.str(self)}
76
if(fmt.type && fmt.type!='s'){
77
throw _b_.ValueError("Unknown format code '"+fmt.type+
78
"' for object of type 'str'")
79
}
80
return self
81
}
82
83
$StringDict.__format__ = function(self, format_spec) {
84
var fmt = new $B.parse_format_spec(format_spec)
85
// For strings, alignment default to left
86
fmt.align = fmt.align || '<'
87
return $B.format_width(preformat(self, fmt), fmt)
88
}
89
90
$StringDict.__getitem__ = function(self,arg){
91
if(isinstance(arg,_b_.int)){
92
var pos = arg
93
if(arg<0) pos+=self.length
94
if(pos>=0 && pos<self.length) return self.charAt(pos)
95
throw _b_.IndexError('string index out of range')
96
}
97
if(isinstance(arg,slice)) {
98
var s=_b_.slice.$dict.$conv_for_seq(arg, self.length),
99
start=s.start, stop=s.stop, step=s.step
100
var res = '',i=null
101
if(step>0){
102
if(stop<=start) return ''
103
for(var i=start;i<stop;i+=step) res += self.charAt(i)
104
} else {
105
if(stop>=start) return ''
107
}
108
return res
109
}
110
if(isinstance(arg,bool)) return self.__getitem__(_b_.int(arg))
115
if (self === undefined) {
116
return $StringDict.__hashvalue__ || $B.$py_next_hash-- // for hash of string type (not instance of string)
117
}
118
119
//http://stackoverflow.com/questions/2909106/python-whats-a-correct-and-good-way-to-implement-hash
120
// this implementation for strings maybe good enough for us..
121
122
var hash=1;
124
hash=(101*hash + self.charCodeAt(i)) & 0xFFFFFFFF
125
}
126
127
return hash
128
}
129
130
$StringDict.__init__ = function(self,arg){
131
self.valueOf = function(){return arg}
132
self.toString = function(){return arg}
134
}
135
136
var $str_iterator = $B.$iterator_class('str_iterator')
137
$StringDict.__iter__ = function(self){
138
var items = self.split('') // list of all characters in string
139
return $B.$iterator(items,$str_iterator)
140
}
141
142
$StringDict.__len__ = function(self){return self.length}
143
146
var kwarg_key = new RegExp('([^\\)]*)\\)')
147
148
var NotANumber = function() {
149
this.name = 'NotANumber'
150
}
151
152
var number_check=function(s) {
153
if(!isinstance(s,[_b_.int,_b_.float])){
154
throw new NotANumber()
155
}
156
}
157
158
var get_char_array = function(size, char) {
159
if (size <= 0)
160
return ''
161
return new Array(size + 1).join(char)
162
}
163
164
var format_padding = function(s, flags, minus_one) {
165
var padding = flags.padding
166
if (!padding) { // undefined
167
return s
168
}
169
s = s.toString()
170
padding = parseInt(padding, 10)
171
if (minus_one) { // numeric formatting where sign goes in front of padding
172
padding -= 1
173
}
174
if (!flags.left) {
175
return get_char_array(padding - s.length, flags.pad_char) + s
176
} else {
177
// left adjusted
178
return s + get_char_array(padding - s.length, flags.pad_char)
179
}
180
}
181
182
var format_int_precision = function(val, flags) {
183
var precision = flags.precision
184
if (!precision) {
185
return val.toString()
186
}
187
precision = parseInt(precision, 10)
188
var s
189
if (val.__class__ === $B.LongInt.$dict) {
190
s=$B.LongInt.$dict.to_base(val, 10)
191
} else {
192
s=val.toString()
193
}
194
if (s[0] === '-') {
195
return '-' + get_char_array(precision - s.length + 1, '0') + s.slice(1)
196
}
197
return get_char_array(precision - s.length, '0') + s
198
}
199
200
var format_float_precision = function(val, upper, flags, modifier) {
201
var precision = flags.precision
202
// val is a float
203
if (isFinite(val)) {
204
val = modifier(val, precision, flags, upper)
205
return val
206
}
207
if (val === Infinity) {
208
val = 'inf'
209
} else if (val === -Infinity) {
210
val = '-inf'
211
} else {
212
val = 'nan'
213
}
214
if (upper) {
215
return val.toUpperCase()
216
}
217
return val
219
}
220
221
var format_sign = function(val, flags) {
222
if (flags.sign) {
223
if (val >= 0) {
224
return "+"
226
} else if (flags.space) {
227
if (val >= 0) {
228
return " "
229
}
230
}
231
return ""
232
}
234
var str_format = function(val, flags) {
235
// string format supports left and right padding
236
flags.pad_char = " " // even if 0 padding is defined, don't use it
237
return format_padding(str(val), flags)
238
}
242
if (val.__class__ === $B.LongInt.$dict) {
243
val = $B.LongInt.$dict.to_base(val, 10)
244
} else {
245
val = parseInt(val)
246
}
247
248
var s = format_int_precision(val, flags)
249
if (flags.pad_char === '0') {
250
if (val < 0) {
251
s = s.substring(1)
252
return '-' + format_padding(s, flags, true)
253
}
254
var sign = format_sign(val, flags)
255
if (sign !== '') {
256
return sign + format_padding(s, flags, true)
257
}
258
}
259
260
return format_padding(format_sign(val, flags) + s, flags)
261
}
263
var repr_format = function(val, flags) {
264
flags.pad_char = " " // even if 0 padding is defined, don't use it
265
return format_padding(repr(val), flags)
266
}
268
var ascii_format = function(val, flags) {
269
flags.pad_char = " " // even if 0 padding is defined, don't use it
270
return format_padding(ascii(val), flags)
271
}
273
// converts to val to float and sets precision if missing
274
var _float_helper = function(val, flags) {
275
number_check(val)
276
if (!flags.precision) {
277
if (!flags.decimal_point) {
278
flags.precision = 6
279
} else {
280
flags.precision = 0
281
}
282
} else {
283
flags.precision = parseInt(flags.precision, 10)
284
validate_precision(flags.precision)
285
}
286
return parseFloat(val)
287
}
289
// used to capture and remove trailing zeroes
290
var trailing_zeros = /(.*?)(0+)([eE].*)/
291
var leading_zeros = /\.(0*)/
292
var trailing_dot = /\.$/
294
var validate_precision = function(precision) {
295
// force precision to limits of javascript
297
}
298
299
// gG
300
var floating_point_format = function(val, upper, flags) {
301
val = _float_helper(val, flags)
302
var v = val.toString()
303
var v_len = v.length
304
var dot_idx = v.indexOf('.')
305
if (dot_idx < 0) {
306
dot_idx = v_len
307
}
308
if (val < 1 && val > -1) {
309
var zeros = leading_zeros.exec(v)
310
var numzeros
311
if (zeros) {
312
numzeros = zeros[1].length
313
} else {
314
numzeros = 0
315
}
316
if (numzeros >= 4) {
317
val = format_sign(val, flags) + format_float_precision(val, upper, flags, _floating_g_exp_helper)
318
if (!flags.alternate) {
319
var trl = trailing_zeros.exec(val)
320
if (trl) {
321
val = trl[1].replace(trailing_dot, '') + trl[3] // remove trailing
327
}
328
return format_padding(val, flags)
329
}
330
flags.precision += numzeros
331
return format_padding(format_sign(val, flags) + format_float_precision(val, upper, flags,
332
function(val, precision) {
333
val = val.toFixed(min(precision, v_len - dot_idx) + numzeros)
334
}), flags)
335
}
336
337
if (dot_idx > flags.precision) {
338
val = format_sign(val, flags) + format_float_precision(val, upper, flags, _floating_g_exp_helper)
339
if (!flags.alternate) {
340
var trl = trailing_zeros.exec(val)
341
if (trl) {
342
val = trl[1].replace(trailing_dot, '') + trl[3] // remove trailing
343
}
344
} else {
345
if (flags.precision <= 1) {
346
val = val[0] + '.' + val.substring(1)
347
}
348
}
349
return format_padding(val, flags)
350
}
351
return format_padding(format_sign(val, flags) + format_float_precision(val, upper, flags,
352
function(val, precision) {
353
if (!flags.decimal_point) {
354
precision = min(v_len - 1, 6)
355
} else if (precision > v_len) {
356
if (!flags.alternate) {
357
precision = v_len
359
}
360
if (precision < dot_idx) {
361
precision = dot_idx
362
}
363
return val.toFixed(precision - dot_idx)
364
}), flags)
365
}
367
var _floating_g_exp_helper = function(val, precision, flags, upper) {
368
if (precision) {
369
--precision
370
}
371
val = val.toExponential(precision)
372
// pad exponent to two digits
373
var e_idx = val.lastIndexOf('e')
374
if (e_idx > val.length - 4) {
375
val = val.substring(0, e_idx + 2) + '0' + val.substring(e_idx + 2)
376
}
377
if (upper) {
378
return val.toUpperCase()
379
}
380
return val
381
}
382
383
// fF
384
var floating_point_decimal_format = function(val, upper, flags) {
385
val = _float_helper(val, flags)
386
return format_padding(format_sign(val, flags) + format_float_precision(val, upper, flags,
387
function(val, precision, flags) {
388
val = val.toFixed(precision)
389
if (precision === 0 && flags.alternate) {
390
val += '.'
391
}
392
return val
393
}), flags)
394
}
395
396
var _floating_exp_helper = function(val, precision, flags, upper) {
397
val = val.toExponential(precision)
398
// pad exponent to two digits
399
var e_idx = val.lastIndexOf('e')
400
if (e_idx > val.length - 4) {
401
val = val.substring(0, e_idx + 2) + '0' + val.substring(e_idx + 2)
402
}
403
if (upper) {
404
return val.toUpperCase()
405
}
406
return val
407
}
408
409
// eE
410
var floating_point_exponential_format = function(val, upper, flags) {
411
val = _float_helper(val, flags)
412
413
return format_padding(format_sign(val, flags) + format_float_precision(val, upper, flags, _floating_exp_helper), flags)
414
}
415
416
var signed_hex_format = function(val, upper, flags) {
419
420
if (val.__class__ === $B.LongInt.$dict) {
421
ret=$B.LongInt.$dict.to_base(val, 16)
422
} else {
423
ret = parseInt(val)
424
ret = ret.toString(16)
425
}
426
ret = format_int_precision(ret, flags)
427
if (upper) {
428
ret = ret.toUpperCase()
429
}
430
if (flags.pad_char === '0') {
431
if (val < 0) {
432
ret = ret.substring(1)
433
ret = '-' + format_padding(ret, flags, true)
434
}
435
var sign = format_sign(val, flags)
436
if (sign !== '') {
437
ret = sign + format_padding(ret, flags, true)
439
}
440
441
if (flags.alternate) {
442
if (ret.charAt(0) === '-') {
443
if (upper) {
444
ret = "-0X" + ret.slice(1)
445
} else {
446
ret = "-0x" + ret.slice(1)
447
}
448
} else {
449
if (upper) {
450
ret = "0X" + ret
451
} else {
452
ret = "0x" + ret
453
}
454
}
455
}
456
return format_padding(format_sign(val, flags) + ret, flags)
457
}
461
var ret
462
463
if (val.__class__ === $B.LongInt.$dict) {
464
ret = $B.LongInt.$dict.to_base(8)
465
} else {
466
ret = parseInt(val)
467
ret = ret.toString(8)
468
}
469
472
if (flags.pad_char === '0') {
473
if (val < 0) {
474
ret = ret.substring(1)
475
ret = '-' + format_padding(ret, flags, true)
476
}
477
var sign = format_sign(val, flags)
478
if (sign !== '') {
479
ret = sign + format_padding(ret, flags, true)
480
}
482
483
if (flags.alternate) {
484
if (ret.charAt(0) === '-') {
485
ret = "-0o" + ret.slice(1)
486
} else {
487
ret = "0o" + ret
488
}
490
return format_padding(ret, flags)
491
}
492
493
var single_char_format = function(val, flags) {
494
if(isinstance(val,str) && val.length==1) return val
495
try {
496
val = _b_.int(val) // yes, floats are valid (they are cast to int)
497
} catch (err) {
498
throw _b_.TypeError('%c requires int or char')
499
}
500
return format_padding(chr(val), flags)
501
}
502
503
var num_flag = function(c, flags) {
504
if (c === '0' && !flags.padding && !flags.decimal_point && !flags.left) {
505
flags.pad_char = '0'
506
return
507
}
508
if (!flags.decimal_point) {
509
flags.padding = (flags.padding || "") + c
510
} else {
511
flags.precision = (flags.precision || "") + c
512
}
513
}
514
515
var decimal_point_flag = function(val, flags) {
516
if (flags.decimal_point) {
517
// can only have one decimal point
518
throw new UnsupportedChar()
519
}
520
flags.decimal_point = true
521
}
522
523
var neg_flag = function(val, flags) {
524
flags.pad_char = ' ' // overrides '0' flag
525
flags.left = true
526
}
527
528
var space_flag = function(val, flags) {
529
flags.space = true
530
}
531
532
var sign_flag = function(val, flags) {
533
flags.sign = true
534
}
535
536
var alternate_flag = function(val, flags) {
537
flags.alternate = true
538
}
539
541
's': str_format,
542
'd': num_format,
543
'i': num_format,
544
'u': num_format,
545
'o': octal_format,
546
'r': repr_format,
547
'a': ascii_format,
548
'g': function(val, flags) {return floating_point_format(val, false, flags)},
549
'G': function(val, flags) {return floating_point_format(val, true, flags)},
550
'f': function(val, flags) {return floating_point_decimal_format(val, false, flags)},
551
'F': function(val, flags) {return floating_point_decimal_format(val, true, flags)},
552
'e': function(val, flags) {return floating_point_exponential_format(val, false, flags)},
553
'E': function(val, flags) {return floating_point_exponential_format(val, true, flags)},
554
'x': function(val, flags) {return signed_hex_format(val, false, flags)},
555
'X': function(val, flags) {return signed_hex_format(val, true, flags)},
556
'c': single_char_format,
557
'0': function(val, flags) {return num_flag('0', flags)},
558
'1': function(val, flags) {return num_flag('1', flags)},
559
'2': function(val, flags) {return num_flag('2', flags)},
560
'3': function(val, flags) {return num_flag('3', flags)},
561
'4': function(val, flags) {return num_flag('4', flags)},
562
'5': function(val, flags) {return num_flag('5', flags)},
563
'6': function(val, flags) {return num_flag('6', flags)},
564
'7': function(val, flags) {return num_flag('7', flags)},
565
'8': function(val, flags) {return num_flag('8', flags)},
566
'9': function(val, flags) {return num_flag('9', flags)},
567
'-': neg_flag,
568
' ': space_flag,
569
'+': sign_flag,
570
'.': decimal_point_flag,
571
'#': alternate_flag
572
}
573
574
// exception thrown when an unsupported char is encountered in legacy format
575
var UnsupportedChar = function() {
576
this.name = "UnsupportedChar"
577
}
578
581
var length = self.length,
582
pos = 0 |0,
583
argpos = null,
584
getitem
585
if (_b_.isinstance(args, _b_.tuple)) {
593
++pos
594
var rslt = kwarg_key.exec(s.substring(newpos))
595
if (!rslt) {
596
throw _b_.ValueError("incomplete format key")
597
}
598
var key = rslt[1]
599
newpos += rslt[0].length
600
try {
602
} catch(err) {
603
if (err.name === "KeyError") {
604
throw err
605
}
606
throw _b_.TypeError("format requires a mapping")
607
}
620
self = args[argpos++]
621
if(self===undefined){
622
throw _b_.TypeError("not enough arguments for format string")
628
// todo: get flags, type
629
// todo: string value based on flags, type, value
630
var flags = {'pad_char': ' '}
631
do {
638
if (ret !== undefined) {
639
return ret
640
}
641
++newpos
642
}
643
} catch (err) {
644
if (err.name === "UnsupportedChar") {
645
invalid_char = s[newpos]
646
if (invalid_char === undefined) {
647
throw _b_.ValueError("incomplete format")
648
}
649
throw _b_.ValueError("unsupported format character '" + invalid_char +
650
"' (0x" + invalid_char.charCodeAt(0).toString(16) + ") at index " + newpos)
651
} else if (err.name === "NotANumber") {
652
var try_char = s[newpos]
659
}
660
} else {
661
cls = cls.__name__
662
}
663
throw _b_.TypeError("%" + try_char + " format: a number is required, not " + cls)
664
} else {
665
throw err
666
}
689
}
690
}
691
} else {
692
// % at end of string
693
throw _b_.ValueError("incomplete format")
694
}
695
pos = newpos + 1
696
} while (pos < length)
697
698
if(argpos!==null){
699
if(args.length>argpos){
700
throw _b_.TypeError('not enough arguments for format string')
701
}else if(args.length<argpos){
702
throw _b_.TypeError('not all arguments converted during string formatting')
703
}
704
}else if(nbph==0){
705
throw _b_.TypeError('not all arguments converted during string formatting')
706
}
713
var $=$B.args('__mul__',2,{self:null,other:null},['self','other'],
714
arguments,{},null,null)
720
return $res
721
}
722
723
$StringDict.__ne__ = function(self,other){return other!==self.valueOf()}
724
725
$StringDict.__repr__ = function(self){
726
var res = self.replace(/\n/g,'\\\\n')
727
// escape the escape char
728
res = res.replace(/\\/g, '\\\\')
729
if(res.search('"')==-1 && res.search("'")==-1){
730
return "'"+res+"'"
736
return res
737
}
738
739
$StringDict.__setitem__ = function(self,attr,value){
740
throw _b_.TypeError("'str' object does not support item assignment")
741
}
742
$StringDict.__str__ = function(self){
743
if(self===undefined) return "<class 'str'>"
744
return self.toString()
745
}
746
$StringDict.toString = function(){return 'string!'}
747
748
// generate comparison methods
749
var $comp_func = function(self,other){
750
if(typeof other !=="string"){throw _b_.TypeError(
751
"unorderable types: 'str' > "+$B.get_class(other).__name__+"()")}
752
return self > other
753
}
754
$comp_func += '' // source code
755
var $comps = {'>':'gt','>=':'ge','<':'lt','<=':'le'}
756
for(var $op in $comps){
757
eval("$StringDict.__"+$comps[$op]+'__ = '+$comp_func.replace(/>/gm,$op))
758
}
759
760
// add "reflected" methods
761
$B.make_rmethods($StringDict)
762
763
// unsupported operations
764
var $notimplemented = function(self,other){
765
throw NotImplementedError("OPERATOR not implemented for class str")
766
}
767
768
$StringDict.title = unicode.title;
769
$StringDict.capitalize = unicode.capitalize;
770
$StringDict.casefold = unicode.casefold;
771
$StringDict.islower = unicode.islower;
772
$StringDict.isupper = unicode.isupper;
773
$StringDict.istitle = unicode.istitle;
774
$StringDict.isspace = unicode.isspace;
775
$StringDict.isalpha = unicode.isalpha;
776
$StringDict.isalnum = unicode.isalnum;
777
$StringDict.isdecimal = unicode.isdecimal;
778
$StringDict.isdigit = unicode.isdigit;
779
$StringDict.isnumeric = unicode.isnumeric;
780
$StringDict.isidentifier = unicode.isidentifier;
781
$StringDict.isprintable = unicode.isprintable;
782
$StringDict.lower = unicode.lower;
783
$StringDict.swapcase = unicode.swapcase;
784
$StringDict.upper = unicode.upper;
787
var $=$B.args("center",3,
788
{self:null, width:null, fillchar:null},
789
['self', 'width', 'fillchar'],
790
arguments,{fillchar:' '},null,null)
791
792
if($.width<=self.length) return self
801
$StringDict.count = function(){
802
var $ = $B.args('count', 4, {self:null, sub:null, start:null, stop:null},
807
var substr = $.self
808
if($.start!==null){
809
var _slice
810
if($.stop!==null){_slice = _b_.slice($.start, $.stop)}
811
else{_slice = _b_.slice($.start,$.self.length)}
812
substr = $StringDict.__getitem__.apply(null, [$.self].concat(_slice))
813
}else{
814
if($.self.length+$.sub.length==0){return 1} // ''.count('') = 1
815
}
816
if($.sub.length==0){
817
if($.start==$.self.length){return 1} // 'aaa'.count('',3) = 1
818
else if(substr.length==0){return 0} // 'aaa'.count('',4) = 0
819
return substr.length+1
820
}
821
var n=0, pos=0
822
while(pos<substr.length){
823
pos=substr.indexOf($.sub,pos)
825
}
826
return n
827
}
828
829
$StringDict.encode = function(self, encoding) {
830
if (encoding === undefined) encoding='utf-8'
831
if(encoding=='rot13' || encoding=='rot_13'){
832
// Special case : returns a string
833
var res = ''
834
for(var i=0, _len = self.length; i<_len ; i++){
835
var char = self.charAt(i)
836
if(('a'<=char && char<='m') || ('A'<=char && char<='M')){
837
res += String.fromCharCode(String.charCodeAt(char)+13)
838
}else if(('m'<char && char<='z') || ('M'<char && char<='Z')){
839
res += String.fromCharCode(String.charCodeAt(char)-13)
840
}else{res += char}
841
}
842
return res
843
}
848
// Return True if the string ends with the specified suffix, otherwise
849
// return False. suffix can also be a tuple of suffixes to look for.
850
// With optional start, test beginning at that position. With optional
851
// end, stop comparing at that position.
853
{self:null, suffix:null, start:null, end:null},
854
['self', 'suffix', 'start', 'end'],
855
arguments,{start:0, end:null},null,null)
856
857
normalize_start_end($)
858
859
var suffixes = $.suffix
865
if(!_b_.isinstance(suffix, str)){throw _b_.TypeError(
866
"endswith first arg must be str or a tuple of str, not int")}
867
if(suffix.length<=s.length &&
868
s.substr(s.length-suffix.length)==suffix) return true
869
}
870
return false
871
}
872
873
$StringDict.expandtabs = function(self, tabsize) {
874
var $ = $B.args('expandtabs', 2, {self:null, tabsize:null},
875
['self', 'tabsize'], arguments, {tabsize:8}, null, null)
876
var s=$B.$GetInt($.tabsize), col=0,pos=0,res=''
877
if(s==1){return self.replace(/\t/g,' ')}
878
while(pos<self.length){
879
var car = self.charAt(pos)
880
switch(car){
881
case '\t':
882
while(col%s > 0){res += ' ';col++}
883
break
884
case '\r':
885
case '\n':
886
res += car
887
col = 0
888
break
889
default:
890
res += car
891
col++
892
break
893
}
894
pos++
895
}
896
897
return res
901
// Return the lowest index in the string where substring sub is found,
902
// such that sub is contained in the slice s[start:end]. Optional
903
// arguments start and end are interpreted as in slice notation.
904
// Return -1 if sub is not found.
913
throw _b_.TypeError(
914
"slice indices must be integers or None or have an __index__ method")}
915
var s = $.self.substring($.start,$.end)
916
917
if($.sub.length==0 && $.start==$.self.length){return $.self.length}
918
if(s.length+$.sub.length==0){return -1}
919
920
var last_search = s.length-$.sub.length
921
for(var i=0;i<=last_search;i++){
922
if(s.substr(i, $.sub.length)==$.sub){return $.start+i}
931
// Parse a "format string", as described in the Python documentation
932
// Return a format object. For the format string
933
// a.x[z]!r:...
934
// the object has attributes :
935
// - name : "a"
936
// - name_ext : [".x", "[z]"]
937
// - conv : r
938
// - spec : rest of string after :
940
var elts = fmt_string.split(':'), name, conv, spec, name_ext=[]
941
if(elts.length==1){
942
// No : in the string : it only contains a name
943
name = fmt_string
944
}else{
945
// name is before the first ":"
946
// spec (the format specification) is after
947
name = elts[0]
948
spec = elts.splice(1).join(':')
949
}
950
951
var elts = name.split('!')
952
if(elts.length>1){
953
name=elts[0]
954
conv=elts[1] // conversion flag
955
if(conv.length!==1 || 'ras'.search(conv)==-1){
956
throw _b_.ValueError('wrong conversion flag '+conv)
957
}
958
}
960
if(name!==undefined){
961
// "name' may be a subscription or attribute
962
// Put these "extensions" in the list "name_ext"
963
function name_repl(match){
964
name_ext.push(match)
965
return ''
966
}
967
var name_ext_re = /\.[_a-zA-Z][_a-zA-Z0-9]*|\[[_a-zA-Z][_a-zA-Z0-9]*\]|\[[0-9]+\]/g
968
name = name.replace(name_ext_re, name_repl)
969
}
978
arguments, {}, 'args', 'kw')
979
980
// Parse self to detect formatting instructions
981
// Create a list "parts" made of sections of the string :
982
// - elements of even rank are literal text
983
// - elements of odd rank are "format objects", built from the
984
// format strings in self (of the form {...})
991
992
while(pos<_len){
993
car = self.charAt(pos)
994
if(car=='{' && self.charAt(pos+1)=='{'){
995
// replace {{ by literal {
996
text += '{'
997
pos+=2
998
}else if(car=='}' && self.charAt(pos+1)=='}'){
999
// replace }} by literal }
1000
text += '}'
1001
pos+=2
1002
}else if(car=='{'){
1003
// Start of a format string
1004
1005
// Store current literal text
1006
parts.push(text)
1007
1008
// Search the end of the format string, ie the } closing the
1009
// opening {. Since the string can contain other pairs {} for
1010
// nested formatting, an integer nb is incremented for each { and
1011
// decremented for each } ; the end of the format string is
1012
// reached when nb==0
1013
var end = pos+1, nb=1
1014
while(end<_len){
1015
if(self.charAt(end)=='{'){nb++;end++}
1016
else if(self.charAt(end)=='}'){
1017
nb--;end++
1018
if(nb==0){
1019
// End of format string
1020
var fmt_string = self.substring(pos+1, end-1)
1021
1022
// Create a format object, by function parse_format
1023
var fmt_obj = parse_format(fmt_string)
1024
1025
// If no name is explicitely provided, use the rank
1026
if(!fmt_obj.name){
1027
fmt_obj.name=rank+''
1028
rank++
1029
}
1033
// In this case, evaluate them using the positional
1034
// or keyword arguments passed to format()
1036
if(/\d+/.exec(key)){
1037
// If key is numeric, search in positional
1038
// arguments
1039
return _b_.tuple.$dict.__getitem__($.args,
1040
parseInt(key))
1041
}else{
1042
// Else try in keyword arguments
1043
return _b_.dict.$dict.__getitem__($.kw, key)
1044
}
1045
}
1046
fmt_obj.spec = fmt_obj.spec.replace(/\{(.+?)\}/g,
1047
replace_nested)
1048
}
1049
1050
// Store format object in list "parts"
1051
parts.push(fmt_obj)
1052
text = ''
1053
break
1054
}
1055
}else{end++}
1057
if(nb>0){throw ValueError("wrong format "+self)}
1058
pos = end
1059
}else{text += car;pos++}
1063
// Apply formatting to the values passed to format()
1064
var res = '', fmt
1065
for(var i=0;i<parts.length;i++){
1066
// Literal text is added unchanged
1067
if(typeof parts[i]=='string'){res += parts[i];continue}
1068
1069
// Format objects
1070
fmt = parts[i]
1071
if(fmt.name.charAt(0).search(/\d/)>-1){
1072
// Numerical reference : use positional arguments
1073
var pos = parseInt(fmt.name),
1074
value = _b_.tuple.$dict.__getitem__($.args, pos)
1075
}else{
1076
// Use keyword arguments
1077
var value = _b_.dict.$dict.__getitem__($.kw, fmt.name)
1078
}
1079
// If name has extensions (attributes or subscriptions)
1080
for(var j=0;j<fmt.name_ext.length;j++){
1081
var ext = fmt.name_ext[j]
1082
if(ext.charAt(0)=='.'){
1083
// Attribute
1084
value = _b_.getattr(value, ext.substr(1))
1085
}else{
1086
// Subscription
1087
var key = ext.substr(1, ext.length-2)
1088
// An index made of digits is transformed into an integer
1089
if(key.charAt(0).search(/\d/)>-1){key = parseInt(key)}
1090
value = _b_.getattr(value, '__getitem__')(key)
1091
}
1092
}
1093
// If the conversion flag is set, first call a function to convert
1094
// the value
1095
if(fmt.conv=='a'){value = _b_.ascii(value)}
1096
else if(fmt.conv=='r'){value = _b_.repr(value)}
1097
else if(fmt.conv=='s'){value = _b_.str(value)}
1098
1099
// Call attribute __format__ to perform the actual formatting
1100
res += _b_.getattr(value, '__format__')(fmt.spec)
1103
}
1104
1105
$StringDict.format_map = function(self) {
1106
throw NotImplementedError("function format_map not implemented yet");
1107
}
1108
1109
$StringDict.index = function(self){
1110
// Like find(), but raise ValueError when the substring is not found.
1112
if(res===-1) throw _b_.ValueError("substring not found")
1113
return res
1114
}
1115
1116
$StringDict.join = function(){
1117
var $=$B.args('join',2,{self:null,iterable:null},
1118
['self', 'iterable'], arguments, {}, null, null)
1119
1120
var iterable=_b_.iter($.iterable)
1121
var res = [],count=0
1125
if(!isinstance(obj2,str)){throw _b_.TypeError(
1126
"sequence item "+count+": expected str instance, "+$B.get_class(obj2).__name__+" found")}
1136
$StringDict.ljust = function(self) {
1137
var $=$B.args('ljust',3,{self:null,width:null,fillchar:null},
1138
['self','width','fillchar'],arguments,{fillchar:' '},null,null)
1139
1140
if ($.width <= self.length) return self
1141
return self + $.fillchar.repeat($.width - self.length)
1145
var $=$B.args('lstrip',2,{self:null,chars:null},['self','chars'],
1146
arguments,{chars:_b_.None},null,null)
1147
if($.chars===_b_.None){return $.self.replace(/^\s+/,'')}
1148
return $.self.replace(new RegExp("^["+$.chars+"]*"),"")
1152
$StringDict.maketrans = function() {
1153
var $ = $B.args('maketrans', 3, {x:null,y:null,z:null},['x','y','z'],
1154
arguments, {y:null, z:null}, null, null)
1155
1156
var _t=_b_.dict()
1157
// make 'default' translate table
1158
for(var i=0; i < 256; i++) _t.$numeric_dict[i]=i
1159
1160
if($.y===null && $.z===null){
1161
// If there is only one argument, it must be a dictionary mapping
1162
// Unicode ordinals (integers) or characters (strings of length 1) to
1163
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1164
// keys will then be converted to ordinals.
1165
if(!_b_.isinstance($.x, _b_.dict)){
1166
throw _b_.TypeError('maketrans only argument must be a dict')
1167
}
1168
var items = _b_.list(_b_.dict.$dict.items($.x))
1169
for(var i=0, len=items.length;i<len;i++){
1170
var k = items[i][0], v=items[i][1]
1171
if(!_b_.isinstance(k, _b_.int)){
1172
if(_b_.isinstance(k, _b_.str) && k.length==1){k = _b_.ord(k)}
1173
else{throw _b_.TypeError("dictionary key "+k+
1174
" is not int or 1-char string")}
1175
}
1176
if(v!==_b_.None && !_b_.isinstance(v, [_b_.int, _b_.str])){
1177
throw _b_.TypeError("dictionary value "+v+
1178
" is not None, integer or string")
1179
}
1180
_t.$numeric_dict[k] = v
1181
}
1182
return _t
1183
}else{
1184
// If there are two arguments, they must be strings of equal length,
1185
// and in the resulting dictionary, each character in x will be mapped
1186
// to the character at the same position in y
1187
if(!(_b_.isinstance($.x, _b_.str) && _b_.isinstance($.y, _b_.str))){
1188
throw _b_.TypeError("maketrans arguments must be strings")
1189
}else if($.x.length!==$.y.length){
1190
throw _b_.TypeError("maketrans arguments must be strings or same length")
1191
}else{
1192
var toNone = {}
1193
if($.z!==null){
1194
// If there is a third argument, it must be a string, whose
1195
// characters will be mapped to None in the result
1196
if(!_b_.isinstance($.z, _b_.str)){
1197
throw _b_.TypeError('maketrans third argument must be a string')
1198
}
1199
for(var i=0,len=$.z.length;i<len;i++){
1200
toNone[_b_.ord($.z.charAt(i))] = true
1201
}
1202
}
1203
for(var i=0,len=$.x.length;i<len;i++){
1204
_t.$numeric_dict[_b_.ord($.x.charAt(i))] = _b_.ord($.y.charAt(i))
1205
}
1206
for(var k in toNone){
1207
_t.$numeric_dict[k] = _b_.None
1208
}
1209
return _t
1210
}
1211
}
1214
$StringDict.partition = function() {
1215
var $=$B.args('partition',2,{self:null,sep:null},['self','sep'],
1216
arguments,{},null,null)
1217
if($.sep==''){throw _b_.ValueError('empty separator')}
1218
check_str($.sep)
1219
var i=$.self.indexOf($.sep)
1220
if (i== -1) return _b_.tuple([$.self, '', ''])
1221
return _b_.tuple([$.self.substring(0,i), $.sep,
1222
$.self.substring(i+$.sep.length)])
1229
var re = new RegExp('\\'+specials.charAt(i),'g')
1230
str = str.replace(re, "\\"+specials.charAt(i))
1231
}
1232
return str
1233
}
1234
1235
$StringDict.replace = function(self, old, _new, count) {
1236
// Replaces occurrences of 'old' by '_new'. Count references
1237
// the number of times to replace. In CPython, negative or undefined
1238
// values of count means replace all.
1239
var $ = $B.args('replace', 4, {self:null,old:null,$$new:null,count:null},
1240
['self','old','$$new','count'], arguments, {count:-1},null,null),
1241
count=$.count,self=$.self,old=$.old,_new=$.$$new
1245
// Validate instance type of 'count'
1246
if (!isinstance(count,[_b_.int,_b_.float])) {
1247
throw _b_.TypeError("'" + $B.get_class(count).__name__ +
1248
"' object cannot be interpreted as an integer");
1249
} else if (isinstance(count, _b_.float)) {
1250
throw _b_.TypeError("integer argument expected, got float");
1251
}
1252
if(count==0){return self}
1253
if(count.__class__==$B.LongInt.$dict){count=parseInt(count.value)}
1254
if(old==''){
1255
if(_new==''){return self}
1256
if(self==''){return _new}
1257
var elts=self.split('')
1258
if(count>-1 && elts.length>=count){
1259
var rest = elts.slice(count).join('')
1260
return _new+elts.slice(0, count).join(_new)+rest
1261
}else{return _new+elts.join(_new)+_new}
1262
}else{
1263
var elts = $StringDict.split(self,old,count)
1266
var res = self, pos = -1
1267
if(old.length==0){
1268
var res = _new
1269
for(var i=0;i<elts.length;i++){
1270
res += elts[i]+_new
1271
}
1272
return res+rest
1273
}
1274
1275
if (count < 0) count = res.length;
1276
while (count > 0) {
1277
pos = res.indexOf(old, pos);
1278
if (pos < 0)
1279
break;
1280
res = res.substr(0, pos) + _new + res.substr(pos + old.length);
1281
pos = pos + _new.length;
1282
count--;
1283
}
1284
return res;
1285
}
1286
1287
$StringDict.rfind = function(self){
1288
// Return the highest index in the string where substring sub is found,
1289
// such that sub is contained within s[start:end]. Optional arguments
1290
// start and end are interpreted as in slice notation. Return -1 on failure.
1300
if($.sub.length==0){
1301
if($.start>$.self.length){return -1}
1302
else{return $.self.length}
1303
}
1304
var sublen = $.sub.length
1305
1306
for(var i=$.end-sublen;i>=$.start;i--){
1307
if($.self.substr(i, sublen)==$.sub){return i}
1308
}
1309
return -1
1310
}
1311
1312
$StringDict.rindex = function(){
1313
// Like rfind() but raises ValueError when the substring sub is not found
1315
if(res==-1){throw _b_.ValueError("substring not found")}
1316
return res
1317
}
1318
1319
$StringDict.rjust = function(self) {
1321
{self:null, width:null, fillchar:null},
1322
['self', 'width', 'fillchar'],
1323
arguments,{fillchar:' '},null,null)
1331
var $=$B.args('rpartition',2,{self:null,sep:null},['self','sep'],
1332
arguments,{},null,null)
1333
check_str($.sep)
1334
var self = reverse($.self),
1335
sep = reverse($.sep)
1336
var items = $StringDict.partition(self,sep).reverse()
1337
for(var i=0;i<items.length;i++){
1338
items[i]=items[i].split('').reverse().join('')
1339
}
1340
return items
1344
var $=$B.args("rsplit",3,{self:null,sep:null,maxsplit:null},
1345
['self','sep','maxsplit'],arguments,
1346
{sep:_b_.None, maxsplit:-1},null,null),
1350
var rev_str = reverse($.self),
1351
rev_sep = sep === _b_.None ? sep : reverse($.sep),
1354
// Reverse the list, then each string inside the list
1355
rev_res.reverse()
1356
for(var i=0;i<rev_res.length;i++){
1363
var $=$B.args('rstrip',2,{self:null,chars:null},['self','chars'],
1364
arguments,{chars:_b_.None},null,null)
1365
if($.chars===_b_.None){return $.self.replace(/\s+$/,'')}
1366
return $.self.replace(new RegExp("["+$.chars+"]*$"),"")
1371
var $=$B.args("split",3,{self:null,sep:null,maxsplit:null},
1372
['self','sep','maxsplit'],arguments,
1373
{sep:_b_.None, maxsplit:-1},null,null)
1374
var sep=$.sep,maxsplit=$.maxsplit,self=$.self
1375
if(maxsplit.__class__===$B.LongInt.$dict){maxsplit=parseInt(maxsplit.value)}
1381
var name = ''
1382
while(1){
1383
if(self.charAt(pos).search(/\s/)===-1){
1384
if(name===''){name=self.charAt(pos)}
1385
else{name+=self.charAt(pos)}
1386
}else{
1387
if(name!==''){
1388
res.push(name)
1389
if(maxsplit!==-1&&res.length===maxsplit+1){
1390
res.pop()
1391
res.push(name+self.substr(pos))
1392
return res
1393
}
1394
name=''
1395
}
1396
}
1397
pos++
1398
if(pos>self.length-1){
1399
if(name){res.push(name)}
1400
break
1401
}
1402
}
1403
return res
1404
}else{
1406
if(maxsplit==0){return [self]}
1407
while(pos<self.length){
1408
if(self.substr(pos,seplen)==sep){
1409
res.push(s)
1410
pos += seplen
1411
if(maxsplit>-1 && res.length>=maxsplit){
1412
res.push(self.substr(pos))
1413
return res
1414
}
1415
s= ''
1416
}else{
1417
s += self.charAt(pos)
1418
pos++
1426
$StringDict.splitlines = function(self){
1427
var $=$B.args('splitlines',2,{self:null,keepends:null},
1428
['self','keepends'],arguments,{keepends:false},null,null)
1429
if(!_b_.isinstance($.keepends,[_b_.bool, _b_.int])){
1430
throw _b_.TypeError('integer argument expected, got '+
1431
$B.get_class($.keepends).__name)
1432
}
1433
var keepends = _b_.int($.keepends)
1434
// Remove trailing line breaks
1435
if(keepends){
1440
while(pos<self.length){
1441
if(self.substr(pos,2)=='\r\n'){
1442
res.push(self.substring(start,pos+2))
1443
start = pos+2
1444
pos = start
1445
}else if(self.charAt(pos)=='\r' || self.charAt(pos)=='\n'){
1446
res.push(self.substring(start,pos+1))
1447
start = pos+1
1448
pos = start
1449
}else{pos++}
1450
}
1451
var rest = self.substr(start)
1452
if(rest){res.push(rest)}
1453
return res
1454
}else{
1455
var self = $.self.replace(/[\r\n]$/,'')
1456
return self.split(/\n|\r\n|\r/)
1457
}
1458
}
1461
// Return True if string starts with the prefix, otherwise return False.
1462
// prefix can also be a tuple of prefixes to look for. With optional
1463
// start, test string beginning at that position. With optional end,
1464
// stop comparing string at that position.
1466
{self:null, prefix:null, start:null, end:null},
1467
['self', 'prefix', 'start', 'end'],
1470
normalize_start_end($)
1471
1472
var prefixes = $.prefix
1473
if(!isinstance(prefixes,_b_.tuple)){prefixes=[prefixes]}
1474
1475
var s = $.self.substring($.start,$.end)
1476
for(var i=0, _len_i = prefixes.length; i < _len_i;i++){
1477
prefix = prefixes[i]
1478
if(!_b_.isinstance(prefix, str)){throw _b_.TypeError(
1479
"endswith first arg must be str or a tuple of str, not int")}
1480
if(s.substr(0,prefix.length)==prefix) return true
1486
$StringDict.strip = function(){
1487
var $=$B.args('strip',2,{self:null,chars:null},['self','chars'],
1488
arguments,{chars:_b_.None},null,null)
1489
return $StringDict.rstrip($StringDict.lstrip($.self,$.chars),$.chars)
1505
var $=$B.args('zfill',2,{self:null,width:null},
1506
['self','width'],arguments,{},null,null)
1507
if ($.width <= self.length) {return self}
1508
switch(self.charAt(0)){
1509
case '+':
1510
case '-':
1511
return self.charAt(0)+'0'.repeat($.width-self.length)+self.substr(1)
1512
default:
1513
return '0'.repeat(width - self.length)+self
1514
}
1520
case 'string':
1521
return arg
1522
case 'number':
1523
if(isFinite(arg)){return arg.toString()}
1530
// class or its subclasses, but the attribute __str__ of the
1531
// class metaclass (usually "type") or its subclasses (usually
1532
// "object")
1533
// The metaclass is the attribute __class__ of the class dictionary
1534
var func = $B.$type.__getattribute__(arg.$dict.__class__,'__str__')
1537
}else if(arg.__class__===$B.$type){ // experimental
1538
var func = $B.$type.__getattribute__(arg.__class__,'__str__')
1539
if(func.__func__===_b_.object.$dict.__str__){
1540
return func(arg)
1541
}
1542
return func()
1545
var f = getattr(arg,'__str__')
1546
// XXX fix : if not better than object.__str__, try __repr__
1547
return f()
1548
}
1549
catch(err){
1555
if($B.debug>1){console.log(err)}
1556
console.log('Warning - no method __str__ or __repr__, default to toString', arg)
1558
}
1559
}
1560
}
1561
str.__class__ = $B.$factory
1562
str.$dict = $StringDict
1563
$StringDict.$factory = str
1564
$StringDict.__new__ = function(cls){
1565
if(cls===undefined){
1566
throw _b_.TypeError('str.__new__(): not enough arguments')
1567
}
1568
return {__class__:cls.$dict}
1569
}
1570
1573
// dictionary and factory for subclasses of string
1574
var $StringSubclassDict = {
1575
__class__:$B.$type,
1576
__name__:'str'
1577
}
1578
1579
// the methods in subclass apply the methods in $StringDict to the
1580
// result of instance.valueOf(), which is a Javascript string
1581
for(var $attr in $StringDict){
1582
if(typeof $StringDict[$attr]=='function'){
1583
$StringSubclassDict[$attr]=(function(attr){
1584
return function(){
1590
}
1591
}
1592
return $StringDict[attr].apply(null,args)
1593
}
1594
})($attr)
1595
}
1596
}
1598
1599
// factory for str subclasses
1600
$B.$StringSubclassFactory = {
1601
__class__:$B.$factory,
1602
$dict:$StringSubclassDict
1603
}
1604
1605
_b_.str = str
1606
1607
// Function to parse the 2nd argument of format()
1608
$B.parse_format_spec = function(spec){
1618
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1))!=-1){
1619
// If the second char is also an alignment specifier, the
1620
// first char is the fill value
1621
this.fill = spec.charAt(0)
1622
this.align = spec.charAt(1)
1623
pos = 2
1624
}else{
1625
// The first character defines alignment : fill defaults to ' '
1626
this.align=aligns[align_pos];
1627
this.fill=' ';
1628
pos++
1629
}
1630
}else{
1631
align_pos = aligns.indexOf(spec.charAt(1))
1632
if(spec.charAt(1) && align_pos!=-1){
1633
// The second character defines alignment : fill is the first one
1634
this.align=aligns[align_pos]
1635
this.fill=spec.charAt(0)
1636
pos = 2
1637
}
1638
}
1639
var car = spec.charAt(pos)
1640
if(car=='+'||car=='-'||car==' '){
1641
this.sign=car;
1642
pos++;
1643
car=spec.charAt(pos);
1646
if(car=='0'){
1647
// sign-aware : equivalent to fill=0 and align=='='
1648
this.fill='0'
1649
this.align = '='
1650
pos++;car=spec.charAt(pos)
1651
}
1653
if(this.width===undefined){this.width=car}
1654
else{this.width+=car}
1655
pos++;car=spec.charAt(pos)
1657
if(this.width!==undefined){this.width=parseInt(this.width)}
1658
if(car==','){this.comma=true;pos++;car=spec.charAt(pos)}
1659
if(car=='.'){
1660
if(digits.indexOf(spec.charAt(pos+1))==-1){
1661
throw _b_.ValueError("Missing precision in format spec")
1662
}
1663
this.precision = spec.charAt(pos+1)
1664
pos+=2;car=spec.charAt(pos)
1665
while(car && digits.indexOf(car)>-1){
1666
this.precision+=car;pos++;car=spec.charAt(pos)
1667
}
1668
this.precision = parseInt(this.precision)
1669
}
1670
if(car && types.indexOf(car)>-1){this.type=car;pos++;car=spec.charAt(pos)}
1671
if(pos!==spec.length){
1673
throw _b_.ValueError("Invalid format specifier")
1674
}
1675
}
1676
this.toString = function(){
1677
return (this.fill===undefined ? '' : _b_.str(this.fill))+
1678
(this.align||'')+
1679
(this.sign||'')+
1680
(this.alternate ? '#' : '')+
1681
(this.sign_aware ? '0' : '')+
1682
(this.width || '')+
1683
(this.comma ? ',' : '')+
1684
(this.precision ? '.'+this.precision : '')+
1685
(this.type || '')
1686
}
1687
}
1688
1689
$B.format_width = function(s, fmt){
1690
if(fmt.width && s.length<fmt.width){
1691
var fill=fmt.fill || ' ', align = fmt.align || '<',
1692
missing = fmt.width-s.length
1693
switch(align){
1694
case '<':
1695
return s+fill.repeat(missing)
1696
case '>':
1697
return fill.repeat(missing)+s
1698
case '=':
1699
if('+-'.indexOf(s.charAt(0))>-1){
1700
return s.charAt(0)+fill.repeat(missing)+s.substr(1)