11
11
//! Parameterized string expansion
12
12
13
13
use core:: prelude:: * ;
14
- use core:: { char, vec, util} ;
15
- use core:: num:: strconv:: { SignNone , SignNeg , SignAll , DigAll , to_str_bytes_common} ;
14
+ use core:: { char, int, vec} ;
16
15
use core:: iterator:: IteratorUtil ;
17
16
18
17
#[ deriving( Eq ) ]
@@ -24,21 +23,13 @@ enum States {
24
23
PushParam ,
25
24
CharConstant ,
26
25
CharClose ,
27
- IntConstant ( int ) ,
28
- FormatPattern ( Flags , FormatState ) ,
26
+ IntConstant ,
29
27
SeekIfElse ( int ) ,
30
28
SeekIfElsePercent ( int ) ,
31
29
SeekIfEnd ( int ) ,
32
30
SeekIfEndPercent ( int )
33
31
}
34
32
35
- #[ deriving( Eq ) ]
36
- enum FormatState {
37
- FormatStateFlags ,
38
- FormatStateWidth ,
39
- FormatStatePrecision
40
- }
41
-
42
33
/// Types of parameters a capability can use
43
34
pub enum Param {
44
35
String ( ~str ) ,
@@ -80,6 +71,8 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
80
71
81
72
let mut stack: ~[ Param ] = ~[ ] ;
82
73
74
+ let mut intstate = ~[ ] ;
75
+
83
76
// Copy parameters into a local vector for mutability
84
77
let mut mparams = [ Number ( 0 ) , ..9 ] ;
85
78
for mparams. mut_iter( ) . zip( params. iter( ) ) . advance |( dst, & src) | {
@@ -107,11 +100,26 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
107
100
_ => return Err ( ~"a non-char was used with %c")
108
101
}
109
102
} else { return Err(~" stack is empty") } ,
103
+ 's' => if stack. len( ) > 0 {
104
+ match stack. pop( ) {
105
+ String ( s) => output. push_all( s. as_bytes( ) ) ,
106
+ _ => return Err ( ~"a non-str was used with %s")
107
+ }
108
+ } else { return Err ( ~"stack is empty") } ,
109
+ 'd' => if stack. len( ) > 0 {
110
+ match stack. pop( ) {
111
+ Number ( x) => {
112
+ let s = x. to_str( ) ;
113
+ output. push_all( s. as_bytes( ) )
114
+ }
115
+ _ => return Err ( ~"a non-number was used with %d")
116
+ }
117
+ } else { return Err ( ~"stack is empty") } ,
110
118
'p' => state = PushParam ,
111
119
'P' => state = SetVar ,
112
120
'g' => state = GetVar ,
113
121
'\'' => state = CharConstant ,
114
- '{' => state = IntConstant ( 0 ) ,
122
+ '{' => state = IntConstant ,
115
123
'l' => if stack. len( ) > 0 {
116
124
match stack. pop( ) {
117
125
String ( s) => stack. push( Number ( s. len( ) as int) ) ,
@@ -223,30 +231,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
223
231
( _, _) => return Err ( ~"first two params not numbers with %i")
224
232
} ,
225
233
226
- // printf-style support for %doxXs
227
- 'd' |'o' |'x' |'X' |'s' => if stack. len ( ) > 0 {
228
- let flags = Flags :: new ( ) ;
229
- let res = format ( stack. pop ( ) , FormatOp :: from_char ( cur) , flags) ;
230
- if res. is_err ( ) { return res }
231
- output. push_all ( res. unwrap ( ) )
232
- } else { return Err ( ~"stack is empty") } ,
233
- ':' |'#' |' ' |'.' |'0' ..'9' => {
234
- let mut flags = Flags :: new ( ) ;
235
- let mut fstate = FormatStateFlags ;
236
- match cur {
237
- ':' => ( ) ,
238
- '#' => flags. alternate = true ,
239
- ' ' => flags. space = true ,
240
- '.' => fstate = FormatStatePrecision ,
241
- '0' ..'9' => {
242
- flags. width = ( cur - '0' ) as uint ;
243
- fstate = FormatStateWidth ;
244
- }
245
- _ => util:: unreachable ( )
246
- }
247
- state = FormatPattern ( flags, fstate) ;
248
- }
249
-
250
234
// conditionals
251
235
'?' => ( ) ,
252
236
't' => if stack. len ( ) > 0 {
@@ -304,61 +288,17 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
304
288
return Err ( ~"malformed character constant") ;
305
289
}
306
290
} ,
307
- IntConstant ( i) => {
308
- match cur {
309
- '}' => {
310
- stack. push ( Number ( i) ) ;
311
- state = Nothing ;
312
- }
313
- '0' ..'9' => {
314
- state = IntConstant ( i* 10 + ( ( cur - '0' ) as int ) ) ;
315
- old_state = Nothing ;
316
- }
317
- _ => return Err ( ~"bad int constant")
318
- }
319
- }
320
- FormatPattern ( ref mut flags, ref mut fstate) => {
321
- old_state = Nothing ;
322
- match ( * fstate, cur) {
323
- ( _, 'd' ) |( _, 'o' ) |( _, 'x' ) |( _, 'X' ) |( _, 's' ) => if stack. len ( ) > 0 {
324
- let res = format ( stack. pop ( ) , FormatOp :: from_char ( cur) , * flags) ;
325
- if res. is_err ( ) { return res }
326
- output. push_all ( res. unwrap ( ) ) ;
327
- old_state = state; // will cause state to go to Nothing
328
- } else { return Err ( ~"stack is empty") } ,
329
- ( FormatStateFlags , '#' ) => {
330
- flags. alternate = true ;
331
- }
332
- ( FormatStateFlags , '-' ) => {
333
- flags. left = true ;
334
- }
335
- ( FormatStateFlags , '+' ) => {
336
- flags. sign = true ;
337
- }
338
- ( FormatStateFlags , ' ' ) => {
339
- flags. space = true ;
340
- }
341
- ( FormatStateFlags , '0' ..'9' ) => {
342
- flags. width = ( cur - '0' ) as uint ;
343
- * fstate = FormatStateWidth ;
344
- }
345
- ( FormatStateFlags , '.' ) => {
346
- * fstate = FormatStatePrecision ;
347
- }
348
- ( FormatStateWidth , '0' ..'9' ) => {
349
- let old = flags. width ;
350
- flags. width = flags. width * 10 + ( ( cur - '0' ) as uint ) ;
351
- if flags. width < old { return Err ( ~"format width overflow") }
352
- }
353
- ( FormatStateWidth , '.' ) => {
354
- * fstate = FormatStatePrecision ;
355
- }
356
- ( FormatStatePrecision , '0' ..'9' ) => {
357
- let old = flags. precision ;
358
- flags. precision = flags. precision * 10 + ( ( cur - '0' ) as uint ) ;
359
- if flags. precision < old { return Err ( ~"format precision overflow") }
360
- }
361
- _ => return Err ( ~"invalid format specifier")
291
+ IntConstant => {
292
+ if cur == '}' {
293
+ stack. push ( match int:: parse_bytes ( intstate, 10 ) {
294
+ Some ( n) => Number ( n) ,
295
+ None => return Err ( ~"bad int constant")
296
+ } ) ;
297
+ intstate. clear ( ) ;
298
+ state = Nothing ;
299
+ } else {
300
+ intstate. push ( cur as u8 ) ;
301
+ old_state = Nothing ;
362
302
}
363
303
}
364
304
SeekIfElse ( level) => {
@@ -409,142 +349,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
409
349
Ok ( output)
410
350
}
411
351
412
- #[ deriving ( Eq ) ]
413
- priv struct Flags {
414
- width : uint ,
415
- precision : uint ,
416
- alternate : bool ,
417
- left : bool ,
418
- sign : bool ,
419
- space : bool
420
- }
421
-
422
- impl Flags {
423
- priv fn new ( ) -> Flags {
424
- Flags { width : 0 , precision : 0 , alternate : false ,
425
- left : false , sign : false , space : false }
426
- }
427
- }
428
-
429
- priv enum FormatOp {
430
- FormatDigit ,
431
- FormatOctal ,
432
- FormatHex ,
433
- FormatHEX ,
434
- FormatString
435
- }
436
-
437
- impl FormatOp {
438
- priv fn from_char ( c : char ) -> FormatOp {
439
- match c {
440
- 'd' => FormatDigit ,
441
- 'o' => FormatOctal ,
442
- 'x' => FormatHex ,
443
- 'X' => FormatHEX ,
444
- 's' => FormatString ,
445
- _ => fail ! ( "bad FormatOp char" )
446
- }
447
- }
448
- priv fn to_char ( self ) -> char {
449
- match self {
450
- FormatDigit => 'd' ,
451
- FormatOctal => 'o' ,
452
- FormatHex => 'x' ,
453
- FormatHEX => 'X' ,
454
- FormatString => 's'
455
- }
456
- }
457
- }
458
-
459
- priv fn format ( val : Param , op : FormatOp , flags : Flags ) -> Result < ~[ u8 ] , ~str > {
460
- let mut s = match val {
461
- Number ( d) => {
462
- match op {
463
- FormatString => {
464
- return Err ( ~"non-number on stack with %s")
465
- }
466
- _ => {
467
- let radix = match op {
468
- FormatDigit => 10 ,
469
- FormatOctal => 8 ,
470
- FormatHex |FormatHEX => 16 ,
471
- FormatString => util:: unreachable ( )
472
- } ;
473
- let mut ( s, _) = match op {
474
- FormatDigit => {
475
- let sign = if flags. sign { SignAll } else { SignNeg } ;
476
- to_str_bytes_common ( & d, radix, false , sign, DigAll )
477
- }
478
- _ => to_str_bytes_common ( & ( d as uint ) , radix, false , SignNone , DigAll )
479
- } ;
480
- if flags. precision > s. len ( ) {
481
- let mut s_ = vec:: with_capacity ( flags. precision ) ;
482
- let n = flags. precision - s. len ( ) ;
483
- s_. grow ( n, & ( '0' as u8 ) ) ;
484
- s_. push_all_move ( s) ;
485
- s = s_;
486
- }
487
- assert ! ( !s. is_empty( ) , "string conversion produced empty result" ) ;
488
- match op {
489
- FormatDigit => {
490
- if flags. space && !( s[ 0 ] == '-' as u8 || s[ 0 ] == '+' as u8 ) {
491
- s. unshift ( ' ' as u8 ) ;
492
- }
493
- }
494
- FormatOctal => {
495
- if flags. alternate && s[ 0 ] != '0' as u8 {
496
- s. unshift ( '0' as u8 ) ;
497
- }
498
- }
499
- FormatHex => {
500
- if flags. alternate {
501
- let s_ = util:: replace ( & mut s, ~[ '0' as u8 , 'x' as u8 ] ) ;
502
- s. push_all_move ( s_) ;
503
- }
504
- }
505
- FormatHEX => {
506
- s = s. into_ascii ( ) . to_upper ( ) . into_bytes ( ) ;
507
- if flags. alternate {
508
- let s_ = util:: replace ( & mut s, ~[ '0' as u8 , 'X' as u8 ] ) ;
509
- s. push_all_move ( s_) ;
510
- }
511
- }
512
- FormatString => util:: unreachable ( )
513
- }
514
- s
515
- }
516
- }
517
- }
518
- String ( s) => {
519
- match op {
520
- FormatString => {
521
- let mut s = s. as_bytes_with_null_consume ( ) ;
522
- s. pop ( ) ; // remove the null
523
- if flags. precision > 0 && flags. precision < s. len ( ) {
524
- s. truncate ( flags. precision ) ;
525
- }
526
- s
527
- }
528
- _ => {
529
- return Err ( fmt ! ( "non-string on stack with %%%c" , op. to_char( ) ) )
530
- }
531
- }
532
- }
533
- } ;
534
- if flags. width > s. len ( ) {
535
- let n = flags. width - s. len ( ) ;
536
- if flags. left {
537
- s. grow ( n, & ( ' ' as u8 ) ) ;
538
- } else {
539
- let mut s_ = vec:: with_capacity ( flags. width ) ;
540
- s_. grow ( n, & ( ' ' as u8 ) ) ;
541
- s_. push_all_move ( s) ;
542
- s = s_;
543
- }
544
- }
545
- Ok ( s)
546
- }
547
-
548
352
#[ cfg ( test) ]
549
353
mod test {
550
354
use super :: * ;
@@ -639,20 +443,4 @@ mod test {
639
443
assert ! ( res. is_ok( ) , res. unwrap_err( ) ) ;
640
444
assert_eq ! ( res. unwrap( ) , bytes!( "\\ E[38;5;42m" ) . to_owned( ) ) ;
641
445
}
642
-
643
- #[ test]
644
- fn test_format( ) {
645
- let mut varstruct = Variables :: new( ) ;
646
- let vars = & mut varstruct;
647
- assert_eq!( expand( bytes!( "%p1%s%p2%2 s%p3%2 s%p4%. 2 s") ,
648
- [ String ( ~"foo") , String ( ~"foo") , String ( ~"f") , String ( ~"foo") ] , vars) ,
649
- Ok ( bytes!( "foofoo ffo") . to_owned( ) ) ) ;
650
- assert_eq!( expand( bytes!( "%p1%: -4 . 2 s") , [ String ( ~"foo") ] , vars) ,
651
- Ok ( bytes!( "fo ") . to_owned( ) ) ) ;
652
-
653
- assert_eq ! ( expand( bytes!( "%p1%d%p1%.3d%p1%5d%p1%:+d" ) , [ Number ( 1 ) ] , vars) ,
654
- Ok ( bytes!( "1001 1+1" ) . to_owned( ) ) ) ;
655
- assert_eq ! ( expand( bytes!( "%p1%o%p1%#o%p2%6.4x%p2%#6.4X" ) , [ Number ( 15 ) , Number ( 27 ) ] , vars) ,
656
- Ok ( bytes!( "17017 001b0X001B" ) . to_owned( ) ) ) ;
657
- }
658
446
}
0 commit comments