about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-08-10 16:50:42 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-08-12 23:18:51 -0700
commit1f6afa887b9fbaadda36ce57a3c296f43ed8a084 (patch)
tree4288b946747ca74367b21301bb609f23b5ffdf40
parent6feb58ed84d8dce2aea35a8be9fd8d7b6883f002 (diff)
downloadrust-1f6afa887b9fbaadda36ce57a3c296f43ed8a084.tar.gz
rust-1f6afa887b9fbaadda36ce57a3c296f43ed8a084.zip
Correct the padding on integer types for formatting
-rw-r--r--src/libstd/fmt/mod.rs66
-rw-r--r--src/libstd/fmt/parse.rs38
-rw-r--r--src/libstd/fmt/rt.rs2
-rw-r--r--src/libsyntax/ext/ifmt.rs18
-rw-r--r--src/test/run-pass/ifmt.rs122
5 files changed, 133 insertions, 113 deletions
diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs
index 7085147aaee..eca0b84d208 100644
--- a/src/libstd/fmt/mod.rs
+++ b/src/libstd/fmt/mod.rs
@@ -32,7 +32,7 @@ pub struct Formatter<'self> {
     /// Character used as 'fill' whenever there is alignment
     fill: char,
     /// Boolean indication of whether the output should be left-aligned
-    alignleft: bool,
+    align: parse::Alignment,
     /// Optionally specified integer width that the output should be
     width: Option<uint>,
     /// Optionally specified precision for numeric types
@@ -108,7 +108,7 @@ pub unsafe fn sprintf(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
             precision: None,
             // FIXME(#8248): shouldn't need a transmute
             buf: cast::transmute(&output as &io::Writer),
-            alignleft: false,
+            align: parse::AlignUnknown,
             fill: ' ',
             args: args,
             curarg: args.iter(),
@@ -148,7 +148,7 @@ impl<'self> Formatter<'self> {
             rt::Argument(ref arg) => {
                 // Fill in the format parameters into the formatter
                 self.fill = arg.format.fill;
-                self.alignleft = arg.format.alignleft;
+                self.align = arg.format.align;
                 self.flags = arg.format.flags;
                 setcount(&mut self.width, &arg.format.width);
                 setcount(&mut self.precision, &arg.format.precision);
@@ -251,7 +251,7 @@ impl<'self> Formatter<'self> {
     /// TODO: dox
     pub fn pad_integral(&mut self, s: &[u8], alternate_prefix: &str,
                         positive: bool) {
-        use fmt::parse::{FlagAlternate, FlagSignPlus};
+        use fmt::parse::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad};
 
         let mut actual_len = s.len();
         if self.flags & 1 << (FlagAlternate as uint) != 0 {
@@ -259,20 +259,27 @@ impl<'self> Formatter<'self> {
         }
         if self.flags & 1 << (FlagSignPlus as uint) != 0 {
             actual_len += 1;
-        }
-        if !positive {
+        } else if !positive {
             actual_len += 1;
         }
 
-        let emit = |this: &mut Formatter| {
-            if this.flags & 1 << (FlagSignPlus as uint) != 0 && positive {
-                this.buf.write(['+' as u8]);
-            } else if !positive {
-                this.buf.write(['-' as u8]);
-            }
-            if this.flags & 1 << (FlagAlternate as uint) != 0 {
-                this.buf.write(alternate_prefix.as_bytes());
+        let mut signprinted = false;
+        let sign = |this: &mut Formatter| {
+            if !signprinted {
+                if this.flags & 1 << (FlagSignPlus as uint) != 0 && positive {
+                    this.buf.write(['+' as u8]);
+                } else if !positive {
+                    this.buf.write(['-' as u8]);
+                }
+                if this.flags & 1 << (FlagAlternate as uint) != 0 {
+                    this.buf.write(alternate_prefix.as_bytes());
+                }
+                signprinted = true;
             }
+        };
+
+        let emit = |this: &mut Formatter| {
+            sign(this);
             this.buf.write(s);
         };
 
@@ -280,7 +287,11 @@ impl<'self> Formatter<'self> {
             None => { emit(self) }
             Some(min) if actual_len >= min => { emit(self) }
             Some(min) => {
-                do self.with_padding(min - actual_len) |me| {
+                if self.flags & 1 << (FlagSignAwareZeroPad as uint) != 0 {
+                    self.fill = '0';
+                    sign(self);
+                }
+                do self.with_padding(min - actual_len, parse::AlignRight) |me| {
                     emit(me);
                 }
             }
@@ -292,8 +303,8 @@ impl<'self> Formatter<'self> {
     /// recognized for generic strings are:
     ///
     /// * width - the minimum width of what to emit
-    /// * fill/alignleft - what to emit and where to emit it if the string
-    ///                    provided needs to be padded
+    /// * fill/align - what to emit and where to emit it if the string
+    ///                provided needs to be padded
     /// * precision - the maximum length to emit, the string is truncated if it
     ///               is longer than this length
     ///
@@ -336,15 +347,20 @@ impl<'self> Formatter<'self> {
             // If we're under both the maximum and the minimum width, then fill
             // up the minimum width with the specified string + some alignment.
             Some(width) => {
-                do self.with_padding(width - s.len()) |me| {
+                do self.with_padding(width - s.len(), parse::AlignLeft) |me| {
                     me.buf.write(s.as_bytes());
                 }
             }
         }
     }
 
-    fn with_padding(&mut self, padding: uint, f: &fn(&mut Formatter)) {
-        if self.alignleft {
+    fn with_padding(&mut self, padding: uint,
+                    default: parse::Alignment, f: &fn(&mut Formatter)) {
+        let align = match self.align {
+            parse::AlignUnknown => default,
+            parse::AlignLeft | parse::AlignRight => self.align
+        };
+        if align == parse::AlignLeft {
             f(self);
         }
         let mut fill = [0u8, ..4];
@@ -352,7 +368,7 @@ impl<'self> Formatter<'self> {
         for _ in range(0, padding) {
             self.buf.write(fill.slice_to(len));
         }
-        if !self.alignleft {
+        if align == parse::AlignRight {
             f(self);
         }
     }
@@ -427,7 +443,6 @@ macro_rules! upper_hex(($ty:ident, $into:ident) => {
         }
     }
 })
-
 // Not sure why, but this causes an "unresolved enum variant, struct or const"
 // when inlined into the above macro...
 #[doc(hidden)]
@@ -500,9 +515,10 @@ impl<T> Poly for T {
 //      time.
 impl<T> Pointer for *const T {
     fn fmt(t: &*const T, f: &mut Formatter) {
-        // XXX: formatting args
-        f.buf.write("0x".as_bytes());
-        LowerHex::fmt(&(*t as uint), f);
+        f.flags |= 1 << (parse::FlagAlternate as uint);
+        do ::uint::to_str_bytes(*t as uint, 16) |buf| {
+            f.pad_integral(buf, "0x", true);
+        }
     }
 }
 
diff --git a/src/libstd/fmt/parse.rs b/src/libstd/fmt/parse.rs
index 673ea1d3fa8..0d39ae84a60 100644
--- a/src/libstd/fmt/parse.rs
+++ b/src/libstd/fmt/parse.rs
@@ -47,7 +47,7 @@ pub struct FormatSpec<'self> {
     /// Optionally specified character to fill alignment with
     fill: Option<char>,
     /// Optionally specified alignment
-    align: Option<Alignment>,
+    align: Alignment,
     /// Packed version of various flags provided
     flags: uint,
     /// The integer precision to use
@@ -68,7 +68,7 @@ pub enum Position<'self> {
 
 /// Enum of alignments which are supoprted.
 #[deriving(Eq)]
-pub enum Alignment { AlignLeft, AlignRight }
+pub enum Alignment { AlignLeft, AlignRight, AlignUnknown }
 
 /// Various flags which can be applied to format strings, the meaning of these
 /// flags is defined by the formatters themselves.
@@ -77,6 +77,7 @@ pub enum Flag {
     FlagSignPlus,
     FlagSignMinus,
     FlagAlternate,
+    FlagSignAwareZeroPad,
 }
 
 /// A count is used for the precision and width parameters of an integer, and
@@ -288,7 +289,7 @@ impl<'self> Parser<'self> {
     fn format(&mut self) -> FormatSpec<'self> {
         let mut spec = FormatSpec {
             fill: None,
-            align: None,
+            align: AlignUnknown,
             flags: 0,
             precision: CountImplied,
             width: CountImplied,
@@ -311,9 +312,9 @@ impl<'self> Parser<'self> {
         }
         // Alignment
         if self.consume('<') {
-            spec.align = Some(AlignLeft);
+            spec.align = AlignLeft;
         } else if self.consume('>') {
-            spec.align = Some(AlignRight);
+            spec.align = AlignRight;
         }
         // Sign flags
         if self.consume('+') {
@@ -326,6 +327,9 @@ impl<'self> Parser<'self> {
             spec.flags |= 1 << (FlagAlternate as uint);
         }
         // Width and precision
+        if self.consume('0') {
+            spec.flags |= 1 << (FlagSignAwareZeroPad as uint);
+        }
         spec.width = self.count();
         if self.consume('.') {
             if self.consume('*') {
@@ -597,7 +601,7 @@ mod tests {
     fn fmtdflt() -> FormatSpec<'static> {
         return FormatSpec {
             fill: None,
-            align: None,
+            align: AlignUnknown,
             flags: 0,
             precision: CountImplied,
             width: CountImplied,
@@ -656,7 +660,7 @@ mod tests {
             position: ArgumentIs(3),
             format: FormatSpec {
                 fill: None,
-                align: None,
+                align: AlignUnknown,
                 flags: 0,
                 precision: CountImplied,
                 width: CountImplied,
@@ -671,7 +675,7 @@ mod tests {
             position: ArgumentIs(3),
             format: FormatSpec {
                 fill: None,
-                align: Some(AlignRight),
+                align: AlignRight,
                 flags: 0,
                 precision: CountImplied,
                 width: CountImplied,
@@ -683,7 +687,7 @@ mod tests {
             position: ArgumentIs(3),
             format: FormatSpec {
                 fill: Some('0'),
-                align: Some(AlignLeft),
+                align: AlignLeft,
                 flags: 0,
                 precision: CountImplied,
                 width: CountImplied,
@@ -695,7 +699,7 @@ mod tests {
             position: ArgumentIs(3),
             format: FormatSpec {
                 fill: Some('*'),
-                align: Some(AlignLeft),
+                align: AlignLeft,
                 flags: 0,
                 precision: CountImplied,
                 width: CountImplied,
@@ -710,7 +714,7 @@ mod tests {
             position: ArgumentNext,
             format: FormatSpec {
                 fill: None,
-                align: None,
+                align: AlignUnknown,
                 flags: 0,
                 precision: CountImplied,
                 width: CountIs(10),
@@ -722,7 +726,7 @@ mod tests {
             position: ArgumentNext,
             format: FormatSpec {
                 fill: None,
-                align: None,
+                align: AlignUnknown,
                 flags: 0,
                 precision: CountIs(10),
                 width: CountIsParam(10),
@@ -734,7 +738,7 @@ mod tests {
             position: ArgumentNext,
             format: FormatSpec {
                 fill: None,
-                align: None,
+                align: AlignUnknown,
                 flags: 0,
                 precision: CountIsNextParam,
                 width: CountImplied,
@@ -746,7 +750,7 @@ mod tests {
             position: ArgumentNext,
             format: FormatSpec {
                 fill: None,
-                align: None,
+                align: AlignUnknown,
                 flags: 0,
                 precision: CountIsParam(10),
                 width: CountImplied,
@@ -761,7 +765,7 @@ mod tests {
             position: ArgumentNext,
             format: FormatSpec {
                 fill: None,
-                align: None,
+                align: AlignUnknown,
                 flags: (1 << FlagSignMinus as uint),
                 precision: CountImplied,
                 width: CountImplied,
@@ -773,7 +777,7 @@ mod tests {
             position: ArgumentNext,
             format: FormatSpec {
                 fill: None,
-                align: None,
+                align: AlignUnknown,
                 flags: (1 << FlagSignPlus as uint) | (1 << FlagAlternate as uint),
                 precision: CountImplied,
                 width: CountImplied,
@@ -788,7 +792,7 @@ mod tests {
             position: ArgumentIs(3),
             format: FormatSpec {
                 fill: None,
-                align: None,
+                align: AlignUnknown,
                 flags: 0,
                 precision: CountImplied,
                 width: CountImplied,
diff --git a/src/libstd/fmt/rt.rs b/src/libstd/fmt/rt.rs
index 6feb1d7a848..90763836fc6 100644
--- a/src/libstd/fmt/rt.rs
+++ b/src/libstd/fmt/rt.rs
@@ -36,7 +36,7 @@ pub struct Argument<'self> {
 
 pub struct FormatSpec {
     fill: char,
-    alignleft: bool,
+    align: parse::Alignment,
     flags: uint,
     precision: parse::Count,
     width: parse::Count,
diff --git a/src/libsyntax/ext/ifmt.rs b/src/libsyntax/ext/ifmt.rs
index 6dda3fc26e8..2d839f652d5 100644
--- a/src/libsyntax/ext/ifmt.rs
+++ b/src/libsyntax/ext/ifmt.rs
@@ -317,6 +317,10 @@ impl Context {
     /// Translate a `parse::Piece` to a static `rt::Piece`
     fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::expr {
         let sp = self.fmtsp;
+        let parsepath = |s: &str| {
+            ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
+              self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
+        };
         let rtpath = |s: &str| {
             ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
               self.ecx.ident_of("rt"), self.ecx.ident_of(s)]
@@ -482,20 +486,24 @@ impl Context {
                 let fill = self.ecx.expr_lit(sp, ast::lit_int(fill as i64,
                                                               ast::ty_char));
                 let align = match arg.format.align {
-                    None | Some(parse::AlignLeft) => {
-                        self.ecx.expr_bool(sp, true)
+                    parse::AlignLeft => {
+                        self.ecx.path_global(sp, parsepath("AlignLeft"))
+                    }
+                    parse::AlignRight => {
+                        self.ecx.path_global(sp, parsepath("AlignRight"))
                     }
-                    Some(parse::AlignRight) => {
-                        self.ecx.expr_bool(sp, false)
+                    parse::AlignUnknown => {
+                        self.ecx.path_global(sp, parsepath("AlignUnknown"))
                     }
                 };
+                let align = self.ecx.expr_path(align);
                 let flags = self.ecx.expr_uint(sp, arg.format.flags);
                 let prec = trans_count(arg.format.precision);
                 let width = trans_count(arg.format.width);
                 let path = self.ecx.path_global(sp, rtpath("FormatSpec"));
                 let fmt = self.ecx.expr_struct(sp, path, ~[
                     self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
-                    self.ecx.field_imm(sp, self.ecx.ident_of("alignleft"), align),
+                    self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
                     self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags),
                     self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
                     self.ecx.field_imm(sp, self.ecx.ident_of("width"), width),
diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs
index adb19e23c03..55dc6bd2407 100644
--- a/src/test/run-pass/ifmt.rs
+++ b/src/test/run-pass/ifmt.rs
@@ -95,36 +95,36 @@ pub fn main() {
     // type of the argument. Also, hex/octal/binary should be defined for
     // integers, but they shouldn't emit the negative sign.
     t!(ifmt!("{:d}", -1i), "-1");
-    t!(ifmt!("{:d}", -1i8), "1");
-    t!(ifmt!("{:d}", -1i16), "1");
-    t!(ifmt!("{:d}", -1i32), "1");
-    t!(ifmt!("{:d}", -1i64), "1");
-    t!(ifmt!("{:t}", -1i), "1");
-    t!(ifmt!("{:t}", -1i8), "1");
-    t!(ifmt!("{:t}", -1i16), "1");
-    t!(ifmt!("{:t}", -1i32), "1");
-    t!(ifmt!("{:t}", -1i64), "1");
-    t!(ifmt!("{:x}", -1i), "1");
-    t!(ifmt!("{:x}", -1i8), "1");
-    t!(ifmt!("{:x}", -1i16), "1");
-    t!(ifmt!("{:x}", -1i32), "1");
-    t!(ifmt!("{:x}", -1i64), "1");
-    t!(ifmt!("{:X}", -1i), "1");
-    t!(ifmt!("{:X}", -1i8), "1");
-    t!(ifmt!("{:X}", -1i16), "1");
-    t!(ifmt!("{:X}", -1i32), "1");
-    t!(ifmt!("{:X}", -1i64), "1");
-    t!(ifmt!("{:o}", -1i), "1");
-    t!(ifmt!("{:o}", -1i8), "1");
-    t!(ifmt!("{:o}", -1i16), "1");
-    t!(ifmt!("{:o}", -1i32), "1");
-    t!(ifmt!("{:o}", -1i64), "1");
+    t!(ifmt!("{:d}", -1i8), "-1");
+    t!(ifmt!("{:d}", -1i16), "-1");
+    t!(ifmt!("{:d}", -1i32), "-1");
+    t!(ifmt!("{:d}", -1i64), "-1");
+    t!(ifmt!("{:t}", 1i), "1");
+    t!(ifmt!("{:t}", 1i8), "1");
+    t!(ifmt!("{:t}", 1i16), "1");
+    t!(ifmt!("{:t}", 1i32), "1");
+    t!(ifmt!("{:t}", 1i64), "1");
+    t!(ifmt!("{:x}", 1i), "1");
+    t!(ifmt!("{:x}", 1i8), "1");
+    t!(ifmt!("{:x}", 1i16), "1");
+    t!(ifmt!("{:x}", 1i32), "1");
+    t!(ifmt!("{:x}", 1i64), "1");
+    t!(ifmt!("{:X}", 1i), "1");
+    t!(ifmt!("{:X}", 1i8), "1");
+    t!(ifmt!("{:X}", 1i16), "1");
+    t!(ifmt!("{:X}", 1i32), "1");
+    t!(ifmt!("{:X}", 1i64), "1");
+    t!(ifmt!("{:o}", 1i), "1");
+    t!(ifmt!("{:o}", 1i8), "1");
+    t!(ifmt!("{:o}", 1i16), "1");
+    t!(ifmt!("{:o}", 1i32), "1");
+    t!(ifmt!("{:o}", 1i64), "1");
 
-    t!(ifmt!("{:d}", 1u), "1");
-    t!(ifmt!("{:d}", 1u8), "1");
-    t!(ifmt!("{:d}", 1u16), "1");
-    t!(ifmt!("{:d}", 1u32), "1");
-    t!(ifmt!("{:d}", 1u64), "1");
+    t!(ifmt!("{:u}", 1u), "1");
+    t!(ifmt!("{:u}", 1u8), "1");
+    t!(ifmt!("{:u}", 1u16), "1");
+    t!(ifmt!("{:u}", 1u32), "1");
+    t!(ifmt!("{:u}", 1u64), "1");
     t!(ifmt!("{:t}", 1u), "1");
     t!(ifmt!("{:t}", 1u8), "1");
     t!(ifmt!("{:t}", 1u16), "1");
@@ -147,44 +147,36 @@ pub fn main() {
     t!(ifmt!("{:o}", 1u64), "1");
 
     // Test the flags for formatting integers
-    t!(ifmt!("{:3d}", 1), "1  ");
-    t!(ifmt!("{:>3d}", 1), "  1");
+    t!(ifmt!("{:3d}", 1),  "  1");
+    t!(ifmt!("{:>3d}", 1),  "  1");
+    t!(ifmt!("{:>+3d}", 1), " +1");
+    t!(ifmt!("{:<3d}", 1), "1  ");
     t!(ifmt!("{:#d}", 1), "1");
-    t!(ifmt!("{:#x}", 10u), "0xa");
-    t!(ifmt!("{:#X}", 10u), "0xA");
-    t!(ifmt!("{:#5x}", 10u), "0xa  ");
-    t!(ifmt!("{:#o}", 10u), "0o12");
-
-    // Precision overrides 0-padding
-    // FIXME #2481: Recent gcc's report some of these as warnings
-    /*t!(ifmt!("{:0>6.5d}", 0), ~" 00000");*/
-    /*t!(ifmt!("{:0>6.5u}", 0u), ~" 00000");*/
-    /*t!(ifmt!("{:0>6.5x}", 0u), ~" 00000");*/
-    /*t!(ifmt!("{:0>6.5d}", 10), ~" 00010");*/
-    /*t!(ifmt!("{:0>6.5d}", -10), ~"-00010");*/
-    /*t!(ifmt!("{:0>6.5u}", 10u), ~" 00010");*/
-    /*t!(ifmt!("{:0>6.5s}", ~"t!"), ~"  t!");*/
-    /*t!(ifmt!("{:0>6.5c}", 'A'), ~"     A");*/
-    /*t!(ifmt!("{:0>6.5x}", 127u), ~" 0007f");*/
-    /*t!(ifmt!("{:0>6.5X}", 127u), ~" 0007F");*/
-    /*t!(ifmt!("{:0>6.5o}", 10u), ~" 00012");*/
+    t!(ifmt!("{:#x}", 10), "0xa");
+    t!(ifmt!("{:#X}", 10), "0xA");
+    t!(ifmt!("{:#5x}", 10), "  0xa");
+    t!(ifmt!("{:#o}", 10), "0o12");
+    t!(ifmt!("{:08x}", 10),  "0000000a");
+    t!(ifmt!("{:8x}", 10),   "       a");
+    t!(ifmt!("{:<8x}", 10),  "a       ");
+    t!(ifmt!("{:>8x}", 10),  "       a");
+    t!(ifmt!("{:#08x}", 10), "0x00000a");
+    t!(ifmt!("{:08d}", -10), "-0000010");
+    t!(ifmt!("{:x}", -1u8), "ff");
+    t!(ifmt!("{:X}", -1u8), "FF");
+    t!(ifmt!("{:t}", -1u8), "11111111");
+    t!(ifmt!("{:o}", -1u8), "377");
+    t!(ifmt!("{:#x}", -1u8), "0xff");
+    t!(ifmt!("{:#X}", -1u8), "0xFF");
+    t!(ifmt!("{:#t}", -1u8), "0b11111111");
+    t!(ifmt!("{:#o}", -1u8), "0o377");
 
     // Signed combinations
-    /*t!(ifmt!("{:5d}", 1), ~"    1");*/
-    /*t!(ifmt!("{: >5d}", -1), ~"   -1");*/
-    /*t!(ifmt!("{:+5d}", 1), ~"   +1");*/
-    /*t!(ifmt!("{:+5d}", -1), ~"   -1");*/
-    /*t!(ifmt!("{:0>5d}", 1), ~" 0001");*/
-    /*t!(ifmt!("{:0>5d}", -1), ~"-0001");*/
-    /*t!(ifmt!("{:0>+5d}", 1), ~"+0001");*/
-    /*t!(ifmt!("{:0>+5d}", -1), ~"-0001");*/
-    /*t!(ifmt!("%- 5d", 1), ~" 1   ");*/
-    /*t!(ifmt!("%- 5d", -1), ~"-1   ");*/
-    /*t!(ifmt!("%-+5d", 1), ~"+1   ");*/
-    /*t!(ifmt!("%-+5d", -1), ~"-1   ");*/
-    /*t!(ifmt!("%- 05d", 1), ~" 1   ");*/
-    /*t!(ifmt!("%- 05d", -1), ~"-1   ");*/
-    /*t!(ifmt!("%-+05d", 1), ~"+1   ");*/
-    /*t!(ifmt!("%-+05d", -1), ~"-1   ");*/
+    t!(ifmt!("{:+5d}", 1),  ~"   +1");
+    t!(ifmt!("{:+5d}", -1), ~"   -1");
+    t!(ifmt!("{:05d}", 1),    ~"00001");
+    t!(ifmt!("{:05d}", -1),   ~"-0001");
+    t!(ifmt!("{:+05d}", 1),   ~"+0001");
+    t!(ifmt!("{:+05d}", -1),  ~"-0001");
 }