Hello,

Pádraig Brady wrote, On 12/04/2012 11:30 AM:
> On 12/04/2012 04:25 PM, Assaf Gordon wrote:
> 
> Nothing yet. The plan is to make a numfmt command available with this 
> interface:
> http://lists.gnu.org/archive/html/coreutils/2012-02/msg00085.html
> 

Attached is a stub for such a program (mostly command-line processing, no 
actual conversion yet).

Please let me know if you're willing to eventually include this program (and 
I'll more functionality, tests, docs, etc.).

I tried to follow the existing code conventions in other programs, but all 
comments and suggestions are welcomed.

-gordon

>From bb5162a7521aee6b95c902acc65c1d3800ba4f30 Mon Sep 17 00:00:00 2001
From: Assaf Gordon <assafgor...@gmail.com>
Date: Tue, 4 Dec 2012 15:32:05 -0500
Subject: [PATCH] numfmt: stub code for new program

---
 build-aux/gen-lists-of-programs.sh |    1 +
 src/.gitignore                     |    1 +
 src/numfmt.c                       |  298 ++++++++++++++++++++++++++++++++++++
 3 files changed, 300 insertions(+), 0 deletions(-)
 create mode 100644 src/numfmt.c

diff --git a/build-aux/gen-lists-of-programs.sh b/build-aux/gen-lists-of-programs.sh
index 212ce02..bf63ee3 100755
--- a/build-aux/gen-lists-of-programs.sh
+++ b/build-aux/gen-lists-of-programs.sh
@@ -85,6 +85,7 @@ normal_progs='
     nl
     nproc
     nohup
+    numfmt
     od
     paste
     pathchk
diff --git a/src/.gitignore b/src/.gitignore
index 18cccc1..25573df 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -59,6 +59,7 @@ nice
 nl
 nohup
 nproc
+numfmt
 od
 paste
 pathchk
diff --git a/src/numfmt.c b/src/numfmt.c
new file mode 100644
index 0000000..e513194
--- /dev/null
+++ b/src/numfmt.c
@@ -0,0 +1,298 @@
+/* Reformat numbers like 11505426432 to the more human-readable 11G
+   Copyright (C) 2012 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "argmatch.h"
+#include "error.h"
+#include "system.h"
+#include "xstrtol.h"
+
+/* The official name of this program (e.g., no 'g' prefix).  */
+#define PROGRAM_NAME "numfmt"
+
+#define AUTHORS proper_name ("XXXX")
+
+#define BUFFER_SIZE (16 * 1024)
+
+enum
+{
+  FROM_OPTION = CHAR_MAX + 1,
+  FROM_UNIT_OPTION,
+  TO_OPTION,
+  TO_UNIT_OPTION,
+  ROUND_OPTION,
+  SUFFIX_OPTION
+};
+
+enum scale_type
+{
+scale_none, /* the default: no scaling */
+scale_auto, /* --from only */
+scale_SI,
+scale_IEC,
+scale_custom  /* --to only, custom scale */
+};
+
+static char const *const scale_from_args[] =
+{
+"auto", "SI", "IEC", NULL
+};
+static enum scale_type const scale_from_types[] =
+{
+scale_auto, scale_SI, scale_IEC
+};
+
+static char const *const scale_to_args[] =
+{
+"SI", "IEC", NULL
+};
+static enum scale_type const scale_to_types[] =
+{
+scale_SI, scale_IEC
+};
+
+
+enum round_type
+{
+round_ceiling,
+round_floor,
+round_nearest
+};
+
+static char const *const round_args[] =
+{
+"ceiling","floor","nearest", NULL
+};
+
+static enum round_type const round_types[] =
+{
+round_ceiling,round_floor,round_nearest
+};
+
+static struct option const longopts[] =
+{
+  {"from", required_argument, NULL, FROM_OPTION},
+  {"from-unit", required_argument, NULL, FROM_UNIT_OPTION},
+  {"to", required_argument, NULL, TO_OPTION},
+  {"to-unit", required_argument, NULL, TO_UNIT_OPTION},
+  {"round", required_argument, NULL, ROUND_OPTION},
+  {"format", required_argument, NULL, 'f'},
+  {"suffix", required_argument, NULL, SUFFIX_OPTION},
+  {GETOPT_HELP_OPTION_DECL},
+  {GETOPT_VERSION_OPTION_DECL},
+  {NULL, 0, NULL, 0}
+};
+
+
+enum scale_type scale_from=scale_none;
+enum scale_type scale_to=scale_none;
+enum round_type _round=round_ceiling;
+char const *format_str = NULL;
+const char *suffix = NULL;
+uintmax_t from_unit_size=1;
+uintmax_t to_unit_size=1;
+
+/* Convert a string of decimal digits, N_STRING, with an optional suffinx
+   to an integral value.  Upon successful conversion,
+   return that value.  If it cannot be converted, give a diagnostic and exit.
+*/
+static uintmax_t
+string_to_integer (const char *n_string)
+{
+  strtol_error s_err;
+  uintmax_t n;
+
+  s_err = xstrtoumax (n_string, NULL, 10, &n, "bkKmMGTPEZY0");
+
+  if (s_err == LONGINT_OVERFLOW)
+    {
+      error (EXIT_FAILURE, 0,
+             _("%s: unit size is so large that it is not representable"),
+                n_string);
+    }
+
+  if (s_err != LONGINT_OK)
+    {
+      error (EXIT_FAILURE, 0, _("%s: invalid unit size"), n_string);
+    }
+  return n;
+}
+
+
+
+void
+usage (int status)
+{
+  if (status != EXIT_SUCCESS)
+    emit_try_help ();
+  else
+    {
+      printf (_("\
+Usage: %s [OPTIONS] [NUMBER]\n\
+"),
+          program_name);
+      fputs (_("\
+Reformats NUMBER(s) to/from human-readable values.\n\
+Numbers can be processed either from stdin or command arguments.\n\
+\n\
+"), stdout);
+      fputs (_("\
+  --from=UNIT     Auto-scale input numbers (auto, SI, IEC)\n\
+                  If not specified, input suffixed are ignored.\n\
+  --from-unit=N   Specifiy the input unit size (instead of the default 1).\n\
+  --to=UNIT       Auto-scale output numbres (SI,IEC,<N>).\n\
+                  If not specified, XXXX\n\
+  --to-unit=N     Specifiy the output unit size (instead of the default 1).\n\
+  --rount=METHOD  Round input numbers. METHOD can be:\n\
+                  ceiling (the default), floor, nearest\n\
+  -f, --format=FORMAT   use printf style output FORMAT.\n\
+                        Default output format is %d .\n\
+  --suffix=SUFFIX       XXXX\n\
+  \n\
+"), stdout);
+      fputs (HELP_OPTION_DESCRIPTION, stdout);
+      fputs (VERSION_OPTION_DESCRIPTION, stdout);
+
+      fputs (_("\
+\n\
+UNIT options:\n\
+ auto ('--from' only):\n\
+      1K  = 1000\n\
+      1Ki = 1024\n\
+      1G  = 1000000\n\
+      1Gi = 1048576\n\
+ SI:\n\
+      1K* = 1000\n\
+      (additional suffixes after K/G/T do not alter the scale)\n\
+ IEC:\n\
+      1K* = 1024\n\
+      (additional suffixes after K/G/T do not alter the scale)\n\
+ <N> ('--to' only):\n\
+      Use number N as the scale.\n\
+\n\
+"), stdout);
+
+      printf (_("\
+\n\
+Examples:\n\
+  %s --to=SI 1000           -> \"1K\"\n\
+  echo 1K | %s --from=SI    -> \"1000\"\n\
+  echo 1K | %s --from=IEC   -> \"1024\"\n\
+"),
+              program_name, program_name, program_name);
+      emit_ancillary_info ();
+    }
+  exit (status);
+}
+
+static void format_number(const char* str)
+{
+  printf("Reformatting: %s\n", str);
+}
+
+int
+main (int argc, char **argv)
+{
+  initialize_main (&argc, &argv);
+  set_program_name (argv[0]);
+  setlocale (LC_ALL, "");
+  bindtextdomain (PACKAGE, LOCALEDIR);
+  textdomain (PACKAGE);
+
+  atexit (close_stdout);
+
+  while (true)
+    {
+      int c = getopt_long (argc, argv, "f:", longopts, NULL);
+
+      if (c == -1)
+        break;
+
+      switch (c)
+        {
+        case FROM_OPTION:
+          scale_from = XARGMATCH ("--from", optarg, scale_from_args, scale_from_types);
+          break;
+
+        case FROM_UNIT_OPTION:
+          from_unit_size = string_to_integer(optarg);
+          break;
+
+        case TO_OPTION:
+          //TODO: add custom handling for numeric/custom scale values
+          scale_to = XARGMATCH ("--to", optarg, scale_to_args, scale_to_types);
+          break;
+
+        case TO_UNIT_OPTION:
+          to_unit_size = string_to_integer(optarg);
+          break;
+
+        case ROUND_OPTION:
+          _round = XARGMATCH ("--round", optarg, round_args, round_types);
+          break;
+
+        case 'f':
+          format_str = optarg;
+          break;
+
+        case SUFFIX_OPTION:
+          suffix = optarg;
+          break;
+
+        case_GETOPT_HELP_CHAR;
+        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
+
+        default:
+          usage (EXIT_FAILURE);
+        }
+    }
+
+#if 0
+  printf("scale_from = %d\n", scale_from);
+  printf("scale_to = %d\n", scale_to);
+  printf("from_unit_size = %zu\n", from_unit_size);
+  printf("to_unit_size = %zu\n", to_unit_size);
+  printf("round = %d\n", _round);
+  printf("format = '%s'\n", format_str);
+  printf("suffix = '%s'\n", suffix);
+#endif
+
+  if (argc > optind)
+    {
+    for (; optind < argc; optind++)
+      format_number(argv[optind]);
+    }
+  else
+    {
+      char buf[BUFFER_SIZE + 1];
+
+      //TODO: allow multiple values on each line?
+      //TODO: support '--field=NUM' feature
+      while ( fgets(buf,BUFFER_SIZE,stdin) != NULL )
+        format_number(buf);
+
+      if (ferror(stdin))
+        {
+          error(0,errno,_("error reading input"));
+        }
+    }
+
+  exit (EXIT_SUCCESS);
+}
-- 
1.7.7.4

Reply via email to