maint: update all copyright year number ranges
[platform/upstream/coreutils.git] / src / od.c
index 085d640..e7ec59a 100644 (file)
--- a/src/od.c
+++ b/src/od.c
@@ -1,5 +1,5 @@
 /* od -- dump files in octal and other formats
-   Copyright (C) 92, 1995-2009 Free Software Foundation, Inc.
+   Copyright (C) 1992-2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include <sys/types.h>
 #include "system.h"
 #include "error.h"
+#include "ftoastr.h"
 #include "quote.h"
 #include "xfreopen.h"
 #include "xprintf.h"
 #include "xstrtol.h"
 
-/* The official name of this program (e.g., no `g' prefix).  */
+/* The official name of this program (e.g., no 'g' prefix).  */
 #define PROGRAM_NAME "od"
 
 #define AUTHORS proper_name ("Jim Meyering")
 
-#include <float.h>
-
 /* The default number of input bytes per output line.  */
 #define DEFAULT_BYTES_PER_BLOCK 16
 
-/* The number of decimal digits of precision in a float.  */
-#ifndef FLT_DIG
-# define FLT_DIG 7
-#endif
-
-/* The number of decimal digits of precision in a double.  */
-#ifndef DBL_DIG
-# define DBL_DIG 15
-#endif
-
 #if HAVE_UNSIGNED_LONG_LONG_INT
 typedef unsigned long long int unsigned_long_long_int;
 #else
-/* This is just a place-holder to avoid a few `#if' directives.
+/* This is just a place-holder to avoid a few '#if' directives.
    In this case, the type isn't actually used.  */
 typedef unsigned long int unsigned_long_long_int;
 #endif
@@ -92,20 +81,18 @@ enum output_format
 enum
   {
     FMT_BYTES_ALLOCATED =
-      MAX ((sizeof "%*.99" - 1
+           (sizeof "%*.99" - 1
             + MAX (sizeof "ld",
                    MAX (sizeof PRIdMAX,
                         MAX (sizeof PRIoMAX,
                              MAX (sizeof PRIuMAX,
-                                  sizeof PRIxMAX))))),
-           sizeof "%*.99Le")
+                                  sizeof PRIxMAX)))))
   };
 
 /* Ensure that our choice for FMT_BYTES_ALLOCATED is reasonable.  */
-verify (LDBL_DIG <= 99);
 verify (MAX_INTEGRAL_TYPE_SIZE * CHAR_BIT / 3 <= 99);
 
-/* Each output format specification (from `-t spec' or from
+/* Each output format specification (from '-t spec' or from
    old-style options) is represented by one of these structures.  */
 struct tspec
   {
@@ -169,7 +156,7 @@ static const int width_bytes[] =
   sizeof (long double)
 };
 
-/* Ensure that for each member of `enum size_spec' there is an
+/* Ensure that for each member of 'enum size_spec' there is an
    initializer in the width_bytes array.  */
 verify (ARRAY_CARDINALITY (width_bytes) == N_SIZE_SPECS);
 
@@ -205,7 +192,7 @@ static bool flag_dump_strings;
    offset and pseudo-start address.  */
 static bool traditional;
 
-/* True if an old-style `pseudo-address' was specified.  */
+/* True if an old-style 'pseudo-address' was specified.  */
 static bool flag_pseudo_start;
 
 /* The difference between the old-style pseudo starting address and
@@ -301,8 +288,7 @@ void
 usage (int status)
 {
   if (status != EXIT_SUCCESS)
-    fprintf (stderr, _("Try `%s --help' for more information.\n"),
-             program_name);
+    emit_try_help ();
   else
     {
       printf (_("\
@@ -319,24 +305,38 @@ With no FILE, or when FILE is -, read standard input.\n\
 \n\
 "), stdout);
       fputs (_("\
-All arguments to long options are mandatory for short options.\n\
+If first and second call formats both apply, the second format is assumed\n\
+if the last operand begins with + or (if there are 2 operands) a digit.\n\
+An OFFSET operand means -j OFFSET.  LABEL is the pseudo-address\n\
+at first byte printed, incremented when dump is progressing.\n\
+For OFFSET and LABEL, a 0x or 0X prefix indicates hexadecimal;\n\
+suffixes may be . for octal and b for multiply by 512.\n\
+\n\
 "), stdout);
       fputs (_("\
-  -A, --address-radix=RADIX   decide how file offsets are printed\n\
+Mandatory arguments to long options are mandatory for short options too.\n\
+"), stdout);
+      fputs (_("\
+  -A, --address-radix=RADIX   output format for file offsets.  RADIX is one\n\
+                                of [doxn], for Decimal, Octal, Hex or None\n\
   -j, --skip-bytes=BYTES      skip BYTES input bytes first\n\
 "), stdout);
       fputs (_("\
   -N, --read-bytes=BYTES      limit dump to BYTES input bytes\n\
-  -S, --strings[=BYTES]       output strings of at least BYTES graphic chars\n\
+  -S BYTES, --strings[=BYTES]  output strings of at least BYTES graphic chars.\
+\n\
+                                3 is implied when BYTES is not specified\n\
   -t, --format=TYPE           select output format or formats\n\
   -v, --output-duplicates     do not use * to mark line suppression\n\
-  -w, --width[=BYTES]         output BYTES bytes per output line\n\
-      --traditional           accept arguments in traditional form\n\
+  -w[BYTES], --width[=BYTES]  output BYTES bytes per output line.\n\
+                                32 is implied when BYTES is not specified\n\
+      --traditional           accept arguments in third form above\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
       fputs (_("\
 \n\
+\n\
 Traditional format specifications may be intermixed; they accumulate:\n\
   -a   same as -t a,  select named characters, ignoring high-order bit\n\
   -b   same as -t o1, select octal bytes\n\
@@ -353,17 +353,8 @@ Traditional format specifications may be intermixed; they accumulate:\n\
 "), stdout);
       fputs (_("\
 \n\
-If first and second call formats both apply, the second format is assumed\n\
-if the last operand begins with + or (if there are 2 operands) a digit.\n\
-An OFFSET operand means -j OFFSET.  LABEL is the pseudo-address\n\
-at first byte printed, incremented when dump is progressing.\n\
-For OFFSET and LABEL, a 0x or 0X prefix indicates hexadecimal;\n\
-suffixes may be . for octal and b for multiply by 512.\n\
-"), stdout);
-      fputs (_("\
 \n\
 TYPE is made up of one or more of these specifications:\n\
-\n\
   a          named character, ignoring high-order bit\n\
   c          ASCII character or backslash escape\n\
 "), stdout);
@@ -376,35 +367,38 @@ TYPE is made up of one or more of these specifications:\n\
 "), stdout);
       fputs (_("\
 \n\
-SIZE is a number.  For TYPE in doux, SIZE may also be C for\n\
+SIZE is a number.  For TYPE in [doux], SIZE may also be C for\n\
 sizeof(char), S for sizeof(short), I for sizeof(int) or L for\n\
 sizeof(long).  If TYPE is f, SIZE may also be F for sizeof(float), D\n\
 for sizeof(double) or L for sizeof(long double).\n\
 "), stdout);
       fputs (_("\
 \n\
-RADIX is d for decimal, o for octal, x for hexadecimal or n for none.\n\
-BYTES is hexadecimal with 0x or 0X prefix, and may have a multiplier suffix:\n\
-b 512, kB 1000, K 1024, MB 1000*1000, M 1024*1024,\n\
-GB 1000*1000*1000, G 1024*1024*1024, and so on for T, P, E, Z, Y.\n\
-Adding a z suffix to any type displays printable characters at the end of each\n\
-output line.\n\
+Adding a z suffix to any type displays printable characters at the end of\n\
+each output line.\n\
 "), stdout);
       fputs (_("\
-Option --string without a number implies 3; option --width without a number\n\
-implies 32.  By default, od uses -A o -t oS -w16.\n\
+\n\
+\n\
+BYTES is hex with 0x or 0X prefix, and may have a multiplier suffix:\n\
+  b    512\n\
+  KB   1000\n\
+  K    1024\n\
+  MB   1000*1000\n\
+  M    1024*1024\n\
+and so on for G, T, P, E, Z, Y.\n\
 "), stdout);
-      emit_bug_reporting_address ();
+      emit_ancillary_info ();
     }
   exit (status);
 }
 
 /* Define the print functions.  */
 
-#define PRINT_TYPE(N, T)                                                \
+#define PRINT_FIELDS(N, T, FMT_STRING, ACTION)                          \
 static void                                                             \
 N (size_t fields, size_t blank, void const *block,                      \
-   char const *fmt_string, int width, int pad)                          \
+   char const *FMT_STRING, int width, int pad)                          \
 {                                                                       \
   T const *p = block;                                                   \
   size_t i;                                                             \
@@ -412,11 +406,22 @@ N (size_t fields, size_t blank, void const *block,                      \
   for (i = fields; blank < i; i--)                                      \
     {                                                                   \
       int next_pad = pad * (i - 1) / fields;                            \
-      xprintf (fmt_string, pad_remaining - next_pad + width, *p++);     \
+      int adjusted_width = pad_remaining - next_pad + width;            \
+      T x = *p++;                                                       \
+      ACTION;                                                           \
       pad_remaining = next_pad;                                         \
     }                                                                   \
 }
 
+#define PRINT_TYPE(N, T)                                                \
+  PRINT_FIELDS (N, T, fmt_string, xprintf (fmt_string, adjusted_width, x))
+
+#define PRINT_FLOATTYPE(N, T, FTOASTR, BUFSIZE)                         \
+  PRINT_FIELDS (N, T, fmt_string ATTRIBUTE_UNUSED,                      \
+                char buf[BUFSIZE];                                      \
+                FTOASTR (buf, sizeof buf, 0, 0, x);                     \
+                xprintf ("%*s", adjusted_width, buf))
+
 PRINT_TYPE (print_s_char, signed char)
 PRINT_TYPE (print_char, unsigned char)
 PRINT_TYPE (print_s_short, short int)
@@ -424,11 +429,13 @@ PRINT_TYPE (print_short, unsigned short int)
 PRINT_TYPE (print_int, unsigned int)
 PRINT_TYPE (print_long, unsigned long int)
 PRINT_TYPE (print_long_long, unsigned_long_long_int)
-PRINT_TYPE (print_float, float)
-PRINT_TYPE (print_double, double)
-PRINT_TYPE (print_long_double, long double)
+
+PRINT_FLOATTYPE (print_float, float, ftoastr, FLT_BUFSIZE_BOUND)
+PRINT_FLOATTYPE (print_double, double, dtoastr, DBL_BUFSIZE_BOUND)
+PRINT_FLOATTYPE (print_long_double, long double, ldtoastr, LDBL_BUFSIZE_BOUND)
 
 #undef PRINT_TYPE
+#undef PRINT_FLOATTYPE
 
 static void
 dump_hexl_mode_trailer (size_t n_bytes, const char *block)
@@ -586,13 +593,11 @@ decode_one_format (const char *s_orig, const char *s, const char **next,
   enum size_spec size_spec;
   unsigned long int size;
   enum output_format fmt;
-  const char *pre_fmt_string;
   void (*print_function) (size_t, size_t, void const *, char const *,
                           int, int);
   const char *p;
   char c;
   int field_width;
-  int precision;
 
   assert (tspec != NULL);
 
@@ -642,8 +647,9 @@ decode_one_format (const char *s_orig, const char *s, const char **next,
               if (MAX_INTEGRAL_TYPE_SIZE < size
                   || integral_type_size[size] == NO_SIZE)
                 {
-                  error (0, 0, _("invalid type string %s;\n\
-this system doesn't provide a %lu-byte integral type"), quote (s_orig), size);
+                  error (0, 0, _("invalid type string %s;\nthis system"
+                                 " doesn't provide a %lu-byte integral type"),
+                         quote (s_orig), size);
                   return false;
                 }
               s = p;
@@ -761,8 +767,10 @@ this system doesn't provide a %lu-byte integral type"), quote (s_orig), size);
               if (size > MAX_FP_TYPE_SIZE
                   || fp_type_size[size] == NO_SIZE)
                 {
-                  error (0, 0, _("invalid type string %s;\n\
-this system doesn't provide a %lu-byte floating point type"),
+                  error (0, 0,
+                         _("invalid type string %s;\n"
+                           "this system doesn't provide a %lu-byte"
+                           " floating point type"),
                          quote (s_orig), size);
                   return false;
                 }
@@ -772,35 +780,34 @@ this system doesn't provide a %lu-byte floating point type"),
         }
       size_spec = fp_type_size[size];
 
-      switch (size_spec)
-        {
-        case FLOAT_SINGLE:
-          print_function = print_float;
-          /* FIXME - should we use %g instead of %e?  */
-          pre_fmt_string = "%%*.%de";
-          precision = FLT_DIG;
-          break;
+      {
+        struct lconv const *locale = localeconv ();
+        size_t decimal_point_len =
+          (locale->decimal_point[0] ? strlen (locale->decimal_point) : 1);
 
-        case FLOAT_DOUBLE:
-          print_function = print_double;
-          pre_fmt_string = "%%*.%de";
-          precision = DBL_DIG;
-          break;
+        switch (size_spec)
+          {
+          case FLOAT_SINGLE:
+            print_function = print_float;
+            field_width = FLT_STRLEN_BOUND_L (decimal_point_len);
+            break;
 
-        case FLOAT_LONG_DOUBLE:
-          print_function = print_long_double;
-          pre_fmt_string = "%%*.%dLe";
-          precision = LDBL_DIG;
-          break;
+          case FLOAT_DOUBLE:
+            print_function = print_double;
+            field_width = DBL_STRLEN_BOUND_L (decimal_point_len);
+            break;
 
-        default:
-          abort ();
-        }
+          case FLOAT_LONG_DOUBLE:
+            print_function = print_long_double;
+            field_width = LDBL_STRLEN_BOUND_L (decimal_point_len);
+            break;
 
-      field_width = precision + 8;
-      sprintf (tspec->fmt_string, pre_fmt_string, precision);
-      assert (strlen (tspec->fmt_string) < FMT_BYTES_ALLOCATED);
-      break;
+          default:
+            abort ();
+          }
+
+        break;
+      }
 
     case 'a':
       ++s;
@@ -819,7 +826,7 @@ this system doesn't provide a %lu-byte floating point type"),
       break;
 
     default:
-      error (0, 0, _("invalid character `%c' in type string %s"),
+      error (0, 0, _("invalid character '%c' in type string %s"),
              *s, quote (s_orig));
       return false;
     }
@@ -878,7 +885,7 @@ open_next_file (void)
     }
   while (in_stream == NULL);
 
-  if (limit_bytes_to_format & !flag_dump_strings)
+  if (limit_bytes_to_format && !flag_dump_strings)
     setvbuf (in_stream, NULL, _IONBF, 0);
 
   return ok;
@@ -983,8 +990,7 @@ skip (uintmax_t n_skip)
 
       if (fstat (fileno (in_stream), &file_stats) == 0)
         {
-          /* The st_size field is valid only for regular files
-             (and for symbolic links, which cannot occur here).
+          /* The st_size field is valid for regular files.
              If the number of bytes left to skip is larger than
              the size of the current file, we can decrement n_skip
              and go on to the next file.  Skip this optimization also
@@ -1051,7 +1057,8 @@ skip (uintmax_t n_skip)
 }
 
 static void
-format_address_none (uintmax_t address ATTRIBUTE_UNUSED, char c ATTRIBUTE_UNUSED)
+format_address_none (uintmax_t address ATTRIBUTE_UNUSED,
+                     char c ATTRIBUTE_UNUSED)
 {
 }
 
@@ -1260,7 +1267,7 @@ read_block (size_t n, char *block, size_t *n_bytes_in_buffer)
 /* Return the least common multiple of the sizes associated
    with the format specs.  */
 
-static int
+static int _GL_ATTRIBUTE_PURE
 get_lcm (void)
 {
   size_t i;
@@ -1286,8 +1293,8 @@ parse_old_offset (const char *s, uintmax_t *offset)
   if (s[0] == '+')
     ++s;
 
-  /* Determine the radix we'll use to interpret S.  If there is a `.',
-     it's decimal, otherwise, if the string begins with `0X'or `0x',
+  /* Determine the radix we'll use to interpret S.  If there is a '.',
+     it's decimal, otherwise, if the string begins with '0X'or '0x',
      it's hexadecimal, else octal.  */
   if (strchr (s, '.') != NULL)
     radix = 10;
@@ -1392,7 +1399,7 @@ dump (void)
 }
 
 /* STRINGS mode.  Find each "string constant" in the input.
-   A string constant is a run of at least `string_min' ASCII
+   A string constant is a run of at least 'string_min' ASCII
    graphic (or formatting) characters terminated by a null.
    Based on a function written by Richard Stallman for a
    traditional version of od.  Return true if successful.  */
@@ -1410,7 +1417,7 @@ dump_strings (void)
       size_t i;
       int c;
 
-      /* See if the next `string_min' chars are all printing chars.  */
+      /* See if the next 'string_min' chars are all printing chars.  */
     tryline:
 
       if (limit_bytes_to_format
@@ -1432,7 +1439,7 @@ dump_strings (void)
           buf[i] = c;
         }
 
-      /* We found a run of `string_min' printable characters.
+      /* We found a run of 'string_min' printable characters.
          Now see if it is terminated with a null byte.  */
       while (!limit_bytes_to_format || address < end_offset)
         {
@@ -1455,7 +1462,7 @@ dump_strings (void)
         }
 
       /* If we get here, the string is all printable and null-terminated,
-         so print it.  It is all in `buf' and `i' is its length.  */
+         so print it.  It is all in 'buf' and 'i' is its length.  */
       buf[i] = 0;
       format_address (address - i - 1, ' ');
 
@@ -1513,16 +1520,16 @@ main (int argc, char **argv)
   int n_files;
   size_t i;
   int l_c_m;
-  size_t desired_width IF_LINT (= 0);
+  size_t desired_width IF_LINT ( = 0);
   bool modern = false;
   bool width_specified = false;
   bool ok = true;
   size_t width_per_block = 0;
   static char const multipliers[] = "bEGKkMmPTYZ0";
 
-  /* The old-style `pseudo starting address' to be printed in parentheses
+  /* The old-style 'pseudo starting address' to be printed in parentheses
      after any true address.  */
-  uintmax_t pseudo_start IF_LINT (= 0);
+  uintmax_t pseudo_start IF_LINT ( = 0);
 
   initialize_main (&argc, &argv);
   set_program_name (argv[0]);
@@ -1540,8 +1547,8 @@ main (int argc, char **argv)
   integral_type_size[sizeof (int)] = INT;
   integral_type_size[sizeof (long int)] = LONG;
 #if HAVE_UNSIGNED_LONG_LONG_INT
-  /* If `long int' and `long long int' have the same size, it's fine
-     to overwrite the entry for `long' with this one.  */
+  /* If 'long int' and 'long long int' have the same size, it's fine
+     to overwrite the entry for 'long' with this one.  */
   integral_type_size[sizeof (unsigned_long_long_int)] = LONG_LONG;
 #endif
 
@@ -1549,7 +1556,7 @@ main (int argc, char **argv)
     fp_type_size[i] = NO_SIZE;
 
   fp_type_size[sizeof (float)] = FLOAT_SINGLE;
-  /* The array entry for `double' is filled in after that for `long double'
+  /* The array entry for 'double' is filled in after that for 'long double'
      so that if they are the same size, we avoid any overhead of
      long double computation in libc.  */
   fp_type_size[sizeof (long double)] = FLOAT_LONG_DOUBLE;
@@ -1564,7 +1571,7 @@ main (int argc, char **argv)
   address_pad_len = 7;
   flag_dump_strings = false;
 
-  for (;;)
+  while (true)
     {
       uintmax_t tmp;
       enum strtol_error s_err;
@@ -1600,8 +1607,8 @@ main (int argc, char **argv)
               break;
             default:
               error (EXIT_FAILURE, 0,
-                     _("invalid output address radix `%c'; \
-it must be one character from [doxn]"),
+                     _("invalid output address radix '%c';\
+ it must be one character from [doxn]"),
                      optarg[0]);
               break;
             }
@@ -1742,7 +1749,7 @@ it must be one character from [doxn]"),
         od [file] [[+]offset[.][b]]
   */
 
-  if (!modern | traditional)
+  if (!modern || traditional)
     {
       uintmax_t o1;
       uintmax_t o2;
@@ -1800,7 +1807,7 @@ it must be one character from [doxn]"),
       if (traditional && 1 < n_files)
         {
           error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
-          error (0, 0, "%s\n",
+          error (0, 0, "%s",
                  _("compatibility mode supports at most one file"));
           usage (EXIT_FAILURE);
         }
@@ -1908,7 +1915,7 @@ it must be one character from [doxn]"),
 
   ok &= (flag_dump_strings ? dump_strings () : dump ());
 
-cleanup:;
+cleanup:
 
   if (have_read_stdin && fclose (stdin) == EOF)
     error (EXIT_FAILURE, errno, _("standard input"));