Skip to content

Commit 1f6afa8

Browse files
committed
Correct the padding on integer types for formatting
1 parent 6feb58e commit 1f6afa8

File tree

5 files changed

+133
-113
lines changed

5 files changed

+133
-113
lines changed

src/libstd/fmt/mod.rs

+41-25
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub struct Formatter<'self> {
3232
/// Character used as 'fill' whenever there is alignment
3333
fill: char,
3434
/// Boolean indication of whether the output should be left-aligned
35-
alignleft: bool,
35+
align: parse::Alignment,
3636
/// Optionally specified integer width that the output should be
3737
width: Option<uint>,
3838
/// Optionally specified precision for numeric types
@@ -108,7 +108,7 @@ pub unsafe fn sprintf(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
108108
precision: None,
109109
// FIXME(#8248): shouldn't need a transmute
110110
buf: cast::transmute(&output as &io::Writer),
111-
alignleft: false,
111+
align: parse::AlignUnknown,
112112
fill: ' ',
113113
args: args,
114114
curarg: args.iter(),
@@ -148,7 +148,7 @@ impl<'self> Formatter<'self> {
148148
rt::Argument(ref arg) => {
149149
// Fill in the format parameters into the formatter
150150
self.fill = arg.format.fill;
151-
self.alignleft = arg.format.alignleft;
151+
self.align = arg.format.align;
152152
self.flags = arg.format.flags;
153153
setcount(&mut self.width, &arg.format.width);
154154
setcount(&mut self.precision, &arg.format.precision);
@@ -251,36 +251,47 @@ impl<'self> Formatter<'self> {
251251
/// TODO: dox
252252
pub fn pad_integral(&mut self, s: &[u8], alternate_prefix: &str,
253253
positive: bool) {
254-
use fmt::parse::{FlagAlternate, FlagSignPlus};
254+
use fmt::parse::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad};
255255

256256
let mut actual_len = s.len();
257257
if self.flags & 1 << (FlagAlternate as uint) != 0 {
258258
actual_len += alternate_prefix.len();
259259
}
260260
if self.flags & 1 << (FlagSignPlus as uint) != 0 {
261261
actual_len += 1;
262-
}
263-
if !positive {
262+
} else if !positive {
264263
actual_len += 1;
265264
}
266265

267-
let emit = |this: &mut Formatter| {
268-
if this.flags & 1 << (FlagSignPlus as uint) != 0 && positive {
269-
this.buf.write(['+' as u8]);
270-
} else if !positive {
271-
this.buf.write(['-' as u8]);
272-
}
273-
if this.flags & 1 << (FlagAlternate as uint) != 0 {
274-
this.buf.write(alternate_prefix.as_bytes());
266+
let mut signprinted = false;
267+
let sign = |this: &mut Formatter| {
268+
if !signprinted {
269+
if this.flags & 1 << (FlagSignPlus as uint) != 0 && positive {
270+
this.buf.write(['+' as u8]);
271+
} else if !positive {
272+
this.buf.write(['-' as u8]);
273+
}
274+
if this.flags & 1 << (FlagAlternate as uint) != 0 {
275+
this.buf.write(alternate_prefix.as_bytes());
276+
}
277+
signprinted = true;
275278
}
279+
};
280+
281+
let emit = |this: &mut Formatter| {
282+
sign(this);
276283
this.buf.write(s);
277284
};
278285

279286
match self.width {
280287
None => { emit(self) }
281288
Some(min) if actual_len >= min => { emit(self) }
282289
Some(min) => {
283-
do self.with_padding(min - actual_len) |me| {
290+
if self.flags & 1 << (FlagSignAwareZeroPad as uint) != 0 {
291+
self.fill = '0';
292+
sign(self);
293+
}
294+
do self.with_padding(min - actual_len, parse::AlignRight) |me| {
284295
emit(me);
285296
}
286297
}
@@ -292,8 +303,8 @@ impl<'self> Formatter<'self> {
292303
/// recognized for generic strings are:
293304
///
294305
/// * width - the minimum width of what to emit
295-
/// * fill/alignleft - what to emit and where to emit it if the string
296-
/// provided needs to be padded
306+
/// * fill/align - what to emit and where to emit it if the string
307+
/// provided needs to be padded
297308
/// * precision - the maximum length to emit, the string is truncated if it
298309
/// is longer than this length
299310
///
@@ -336,23 +347,28 @@ impl<'self> Formatter<'self> {
336347
// If we're under both the maximum and the minimum width, then fill
337348
// up the minimum width with the specified string + some alignment.
338349
Some(width) => {
339-
do self.with_padding(width - s.len()) |me| {
350+
do self.with_padding(width - s.len(), parse::AlignLeft) |me| {
340351
me.buf.write(s.as_bytes());
341352
}
342353
}
343354
}
344355
}
345356

346-
fn with_padding(&mut self, padding: uint, f: &fn(&mut Formatter)) {
347-
if self.alignleft {
357+
fn with_padding(&mut self, padding: uint,
358+
default: parse::Alignment, f: &fn(&mut Formatter)) {
359+
let align = match self.align {
360+
parse::AlignUnknown => default,
361+
parse::AlignLeft | parse::AlignRight => self.align
362+
};
363+
if align == parse::AlignLeft {
348364
f(self);
349365
}
350366
let mut fill = [0u8, ..4];
351367
let len = self.fill.encode_utf8(fill);
352368
for _ in range(0, padding) {
353369
self.buf.write(fill.slice_to(len));
354370
}
355-
if !self.alignleft {
371+
if align == parse::AlignRight {
356372
f(self);
357373
}
358374
}
@@ -427,7 +443,6 @@ macro_rules! upper_hex(($ty:ident, $into:ident) => {
427443
}
428444
}
429445
})
430-
431446
// Not sure why, but this causes an "unresolved enum variant, struct or const"
432447
// when inlined into the above macro...
433448
#[doc(hidden)]
@@ -500,9 +515,10 @@ impl<T> Poly for T {
500515
// time.
501516
impl<T> Pointer for *const T {
502517
fn fmt(t: &*const T, f: &mut Formatter) {
503-
// XXX: formatting args
504-
f.buf.write("0x".as_bytes());
505-
LowerHex::fmt(&(*t as uint), f);
518+
f.flags |= 1 << (parse::FlagAlternate as uint);
519+
do ::uint::to_str_bytes(*t as uint, 16) |buf| {
520+
f.pad_integral(buf, "0x", true);
521+
}
506522
}
507523
}
508524

src/libstd/fmt/parse.rs

+21-17
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub struct FormatSpec<'self> {
4747
/// Optionally specified character to fill alignment with
4848
fill: Option<char>,
4949
/// Optionally specified alignment
50-
align: Option<Alignment>,
50+
align: Alignment,
5151
/// Packed version of various flags provided
5252
flags: uint,
5353
/// The integer precision to use
@@ -68,7 +68,7 @@ pub enum Position<'self> {
6868

6969
/// Enum of alignments which are supoprted.
7070
#[deriving(Eq)]
71-
pub enum Alignment { AlignLeft, AlignRight }
71+
pub enum Alignment { AlignLeft, AlignRight, AlignUnknown }
7272

7373
/// Various flags which can be applied to format strings, the meaning of these
7474
/// flags is defined by the formatters themselves.
@@ -77,6 +77,7 @@ pub enum Flag {
7777
FlagSignPlus,
7878
FlagSignMinus,
7979
FlagAlternate,
80+
FlagSignAwareZeroPad,
8081
}
8182

8283
/// A count is used for the precision and width parameters of an integer, and
@@ -288,7 +289,7 @@ impl<'self> Parser<'self> {
288289
fn format(&mut self) -> FormatSpec<'self> {
289290
let mut spec = FormatSpec {
290291
fill: None,
291-
align: None,
292+
align: AlignUnknown,
292293
flags: 0,
293294
precision: CountImplied,
294295
width: CountImplied,
@@ -311,9 +312,9 @@ impl<'self> Parser<'self> {
311312
}
312313
// Alignment
313314
if self.consume('<') {
314-
spec.align = Some(AlignLeft);
315+
spec.align = AlignLeft;
315316
} else if self.consume('>') {
316-
spec.align = Some(AlignRight);
317+
spec.align = AlignRight;
317318
}
318319
// Sign flags
319320
if self.consume('+') {
@@ -326,6 +327,9 @@ impl<'self> Parser<'self> {
326327
spec.flags |= 1 << (FlagAlternate as uint);
327328
}
328329
// Width and precision
330+
if self.consume('0') {
331+
spec.flags |= 1 << (FlagSignAwareZeroPad as uint);
332+
}
329333
spec.width = self.count();
330334
if self.consume('.') {
331335
if self.consume('*') {
@@ -597,7 +601,7 @@ mod tests {
597601
fn fmtdflt() -> FormatSpec<'static> {
598602
return FormatSpec {
599603
fill: None,
600-
align: None,
604+
align: AlignUnknown,
601605
flags: 0,
602606
precision: CountImplied,
603607
width: CountImplied,
@@ -656,7 +660,7 @@ mod tests {
656660
position: ArgumentIs(3),
657661
format: FormatSpec {
658662
fill: None,
659-
align: None,
663+
align: AlignUnknown,
660664
flags: 0,
661665
precision: CountImplied,
662666
width: CountImplied,
@@ -671,7 +675,7 @@ mod tests {
671675
position: ArgumentIs(3),
672676
format: FormatSpec {
673677
fill: None,
674-
align: Some(AlignRight),
678+
align: AlignRight,
675679
flags: 0,
676680
precision: CountImplied,
677681
width: CountImplied,
@@ -683,7 +687,7 @@ mod tests {
683687
position: ArgumentIs(3),
684688
format: FormatSpec {
685689
fill: Some('0'),
686-
align: Some(AlignLeft),
690+
align: AlignLeft,
687691
flags: 0,
688692
precision: CountImplied,
689693
width: CountImplied,
@@ -695,7 +699,7 @@ mod tests {
695699
position: ArgumentIs(3),
696700
format: FormatSpec {
697701
fill: Some('*'),
698-
align: Some(AlignLeft),
702+
align: AlignLeft,
699703
flags: 0,
700704
precision: CountImplied,
701705
width: CountImplied,
@@ -710,7 +714,7 @@ mod tests {
710714
position: ArgumentNext,
711715
format: FormatSpec {
712716
fill: None,
713-
align: None,
717+
align: AlignUnknown,
714718
flags: 0,
715719
precision: CountImplied,
716720
width: CountIs(10),
@@ -722,7 +726,7 @@ mod tests {
722726
position: ArgumentNext,
723727
format: FormatSpec {
724728
fill: None,
725-
align: None,
729+
align: AlignUnknown,
726730
flags: 0,
727731
precision: CountIs(10),
728732
width: CountIsParam(10),
@@ -734,7 +738,7 @@ mod tests {
734738
position: ArgumentNext,
735739
format: FormatSpec {
736740
fill: None,
737-
align: None,
741+
align: AlignUnknown,
738742
flags: 0,
739743
precision: CountIsNextParam,
740744
width: CountImplied,
@@ -746,7 +750,7 @@ mod tests {
746750
position: ArgumentNext,
747751
format: FormatSpec {
748752
fill: None,
749-
align: None,
753+
align: AlignUnknown,
750754
flags: 0,
751755
precision: CountIsParam(10),
752756
width: CountImplied,
@@ -761,7 +765,7 @@ mod tests {
761765
position: ArgumentNext,
762766
format: FormatSpec {
763767
fill: None,
764-
align: None,
768+
align: AlignUnknown,
765769
flags: (1 << FlagSignMinus as uint),
766770
precision: CountImplied,
767771
width: CountImplied,
@@ -773,7 +777,7 @@ mod tests {
773777
position: ArgumentNext,
774778
format: FormatSpec {
775779
fill: None,
776-
align: None,
780+
align: AlignUnknown,
777781
flags: (1 << FlagSignPlus as uint) | (1 << FlagAlternate as uint),
778782
precision: CountImplied,
779783
width: CountImplied,
@@ -788,7 +792,7 @@ mod tests {
788792
position: ArgumentIs(3),
789793
format: FormatSpec {
790794
fill: None,
791-
align: None,
795+
align: AlignUnknown,
792796
flags: 0,
793797
precision: CountImplied,
794798
width: CountImplied,

src/libstd/fmt/rt.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub struct Argument<'self> {
3636

3737
pub struct FormatSpec {
3838
fill: char,
39-
alignleft: bool,
39+
align: parse::Alignment,
4040
flags: uint,
4141
precision: parse::Count,
4242
width: parse::Count,

src/libsyntax/ext/ifmt.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,10 @@ impl Context {
317317
/// Translate a `parse::Piece` to a static `rt::Piece`
318318
fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::expr {
319319
let sp = self.fmtsp;
320+
let parsepath = |s: &str| {
321+
~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
322+
self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
323+
};
320324
let rtpath = |s: &str| {
321325
~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
322326
self.ecx.ident_of("rt"), self.ecx.ident_of(s)]
@@ -482,20 +486,24 @@ impl Context {
482486
let fill = self.ecx.expr_lit(sp, ast::lit_int(fill as i64,
483487
ast::ty_char));
484488
let align = match arg.format.align {
485-
None | Some(parse::AlignLeft) => {
486-
self.ecx.expr_bool(sp, true)
489+
parse::AlignLeft => {
490+
self.ecx.path_global(sp, parsepath("AlignLeft"))
491+
}
492+
parse::AlignRight => {
493+
self.ecx.path_global(sp, parsepath("AlignRight"))
487494
}
488-
Some(parse::AlignRight) => {
489-
self.ecx.expr_bool(sp, false)
495+
parse::AlignUnknown => {
496+
self.ecx.path_global(sp, parsepath("AlignUnknown"))
490497
}
491498
};
499+
let align = self.ecx.expr_path(align);
492500
let flags = self.ecx.expr_uint(sp, arg.format.flags);
493501
let prec = trans_count(arg.format.precision);
494502
let width = trans_count(arg.format.width);
495503
let path = self.ecx.path_global(sp, rtpath("FormatSpec"));
496504
let fmt = self.ecx.expr_struct(sp, path, ~[
497505
self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
498-
self.ecx.field_imm(sp, self.ecx.ident_of("alignleft"), align),
506+
self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
499507
self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags),
500508
self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
501509
self.ecx.field_imm(sp, self.ecx.ident_of("width"), width),

0 commit comments

Comments
 (0)