[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

gEDA-cvs: pcb.git: branch: master updated (6fb3667dc3f76b905572c0964f8349d70a600079)



The branch, master has been updated
       via  6fb3667dc3f76b905572c0964f8349d70a600079 (commit)
      from  fce9e501a4bbfbed10c92b395296440169575955 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


=========
 Summary
=========

 src/Makefile.am  |    2 +
 src/pcb-printf.c |  414 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/pcb-printf.h |   93 ++++++++++++
 3 files changed, 509 insertions(+), 0 deletions(-)
 create mode 100644 src/pcb-printf.c
 create mode 100644 src/pcb-printf.h


=================
 Commit Messages
=================

commit 6fb3667dc3f76b905572c0964f8349d70a600079
Author: Andrew Poelstra <asp11@xxxxxx>
Commit: Andrew Poelstra <asp11@xxxxxx>

    Add pcb-printf.c to allow custom specifiers for unit output
    
    From the header:
    /* This file defines a wrapper around sprintf, that
     *  defines new specifiers that take pcb BDimension
     *  objects as input.
     *
     * The new specifiers are:
     *   %mm    output a measure in mm
     *   %mM    output a measure in scaled (mm/um) metric
     *   %ml    output a measure in mil
     *   %mL    output a measure in scaled (mil/in) imperial
     *   %ms    output a measure in most natural mm/mil units
     *   %mS    output a measure in most natural scaled units
     *   %md    output a pair of measures in most natural mm/mil units
     *   %mD    output a pair of measures in most natural scaled units
     *   %m3    output 3 measures in most natural scaled units
     *     ...
     *   %m9    output 9 measures in most natural scaled units
     *   %m*    output a measure with unit given as an additional
     *          const char* parameter
     *   %mr    output a measure in a unit readable by parse_l.l
     *          (this will always append a unit suffix)
     *
     * These accept the usual printf modifiers for %f,
     *  as well as the additional modifier $ which is
     *  used to output a unit suffix after the measure.
     *
     * KNOWN ISSUES:
     *   No support for %zu size_t printf spec
     *   No support for .* subspecifier for pcb specs
     */

:100644 100644 18fe5c1... 7efb2d7... M	src/Makefile.am
:000000 100644 0000000... 9110a10... A	src/pcb-printf.c
:000000 100644 0000000... 2c11b8f... A	src/pcb-printf.h

=========
 Changes
=========

commit 6fb3667dc3f76b905572c0964f8349d70a600079
Author: Andrew Poelstra <asp11@xxxxxx>
Commit: Andrew Poelstra <asp11@xxxxxx>

    Add pcb-printf.c to allow custom specifiers for unit output
    
    From the header:
    /* This file defines a wrapper around sprintf, that
     *  defines new specifiers that take pcb BDimension
     *  objects as input.
     *
     * The new specifiers are:
     *   %mm    output a measure in mm
     *   %mM    output a measure in scaled (mm/um) metric
     *   %ml    output a measure in mil
     *   %mL    output a measure in scaled (mil/in) imperial
     *   %ms    output a measure in most natural mm/mil units
     *   %mS    output a measure in most natural scaled units
     *   %md    output a pair of measures in most natural mm/mil units
     *   %mD    output a pair of measures in most natural scaled units
     *   %m3    output 3 measures in most natural scaled units
     *     ...
     *   %m9    output 9 measures in most natural scaled units
     *   %m*    output a measure with unit given as an additional
     *          const char* parameter
     *   %mr    output a measure in a unit readable by parse_l.l
     *          (this will always append a unit suffix)
     *
     * These accept the usual printf modifiers for %f,
     *  as well as the additional modifier $ which is
     *  used to output a unit suffix after the measure.
     *
     * KNOWN ISSUES:
     *   No support for %zu size_t printf spec
     *   No support for .* subspecifier for pcb specs
     */

diff --git a/src/Makefile.am b/src/Makefile.am
index 18fe5c1..7efb2d7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -106,6 +106,8 @@ PCB_SRCS = \
 	parse_l.l \
 	parse_y.h \
 	parse_y.y \
+	pcb-printf.c \
+	pcb-printf.h \
 	polygon.c \
 	polygon.h \
 	polygon1.c \
diff --git a/src/pcb-printf.c b/src/pcb-printf.c
new file mode 100644
index 0000000..9110a10
--- /dev/null
+++ b/src/pcb-printf.c
@@ -0,0 +1,414 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 2011 Andrew Poelstra
+ *
+ *  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 2 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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Andrew Poelstra, 16966 60A Ave, V3S 8X5 Surrey, BC, Canada
+ *  asp11@xxxxxx
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "global.h"
+
+#include "pcb-printf.h"
+
+enum e_family { METRIC, IMPERIAL };
+enum e_suffix { NO_SUFFIX, SUFFIX, FILE_MODE };
+
+struct unit {
+  const char *suffix;
+  char printf_code;
+  double scale_factor;
+  enum e_family family;
+  enum e_allow  allow;
+  int default_prec;
+};
+
+/* These should be kept in order of smallest scale_factor
+ * to largest -- the code uses this ordering when finding
+ * the best scale to use for a group of measures */
+static struct unit Units[] = {
+  { "km", 'k', 0.000001, METRIC, ALLOW_KM, 5 },
+  { "m",  'f', 0.001,    METRIC, ALLOW_M,  5 },
+  { "cm", 'e', 0.1,      METRIC, ALLOW_CM, 5 },
+  { "mm", 'm', 1,        METRIC, ALLOW_MM, 4 },
+  { "um", 'u', 1000,     METRIC, ALLOW_UM, 2 },
+  { "nm", 'n', 1000000,  METRIC, ALLOW_NM, 0 },
+
+  { "in",   'i', 0.001, IMPERIAL, ALLOW_IN,   5 },
+  { "mil",  'l', 1,     IMPERIAL, ALLOW_MIL,  2 },
+  { "cmil", 'c', 100,   IMPERIAL, ALLOW_CMIL, 0 }
+};
+#define N_UNITS ((int) (sizeof Units / sizeof Units[0]))
+
+static int min_sig_figs(double d)
+{
+  char buf[50];
+  int rv;
+
+  if(d == 0) return 0;
+
+  /* Normalize to x.xxxx... form */
+  if(d < 0)      d *= -1;
+  while(d >= 10) d /= 10;
+  while(d < 1)   d *= 10;
+
+  rv = sprintf(buf, "%g", d);
+  return rv;
+}
+
+/* Converts a (group of) measurement(s) to a comma-deliminated
+ * string, with appropriate units. If more than one coord is
+ * given, the list is enclosed in parens to make the scope of
+ * the unit suffix clear.  */
+static gchar *CoordsToString(BDimension coord[], int n_coords, const char *printf_spec, enum e_allow allow, enum e_suffix suffix_type)
+{
+  GString *buff;
+  gchar *printf_buff;
+  gchar filemode_buff[G_ASCII_DTOSTR_BUF_SIZE];
+  enum e_family family;
+  double *value;
+  const char *suffix;
+  int i, n;
+
+  value = malloc (n_coords * sizeof *value);
+  buff  = g_string_new ("");
+
+  /* Sanity checks */
+  if (buff == NULL || value == NULL)
+    return NULL;
+  if (allow == 0)
+    allow = ALLOW_ALL;
+  if (printf_spec == NULL)
+    printf_spec = "";
+
+  /* Check our freedom in choosing units */
+  if ((allow & ALLOW_IMPERIAL) == 0)
+    family = METRIC;
+  else if ((allow & ALLOW_METRIC) == 0)
+    family = IMPERIAL;
+  else
+    {
+      int met_votes = 0,
+          imp_votes = 0;
+
+      for (i = 0; i < n_coords; ++i)
+        if(min_sig_figs(COORD_TO_MIL(coord[i])) < min_sig_figs(COORD_TO_MM(coord[i])))
+          ++imp_votes;
+        else
+          ++met_votes;
+
+      if (imp_votes > met_votes)
+        family = IMPERIAL;
+      else
+        family = METRIC;
+    }
+
+  /* Set base unit */
+  for (i = 0; i < n_coords; ++i)
+    {
+      switch (family)
+        {
+        case METRIC:   value[i] = COORD_TO_MM (coord[i]); break;
+        case IMPERIAL: value[i] = COORD_TO_MIL (coord[i]); break;
+        }
+    }
+
+  /* Determine scale factor -- find smallest unit that brings
+   * the whole group above unity */
+  for (n = 0; n < N_UNITS; ++n)
+    {
+      if ((Units[n].allow & allow) != 0 && (Units[n].family == family))
+        {
+          int n_above_one = 0;
+    
+          for (i = 0; i < n_coords; ++i)
+            if (fabs(value[i] * Units[n].scale_factor) > 1)
+              ++n_above_one;
+          if (n_above_one == n_coords)
+            break;
+        }
+    }
+  /* If nothing worked, wind back to the smallest allowable unit */
+  if (n == N_UNITS)
+    {
+      do {
+        --n;
+      } while ((Units[n].allow & allow) == 0 || Units[n].family != family);
+    }
+
+  /* Apply scale factor */
+  suffix = Units[n].suffix;
+  for (i = 0; i < n_coords; ++i)
+    value[i] = value[i] * Units[n].scale_factor;
+
+  /* Create sprintf specifier, using default_prec no preciscion is given */
+  i = 0;
+  while (printf_spec[i] == '%' || isdigit(printf_spec[i]) ||
+         printf_spec[i] == '-' || printf_spec[i] == '+' ||
+         printf_spec[i] == '#' || printf_spec[i] == '0')
+    ++i;
+  if (printf_spec[i] == '.')
+    printf_buff = g_strdup_printf (", %sf", printf_spec);
+  else
+    printf_buff = g_strdup_printf (", %s.%df", printf_spec, Units[n].default_prec);
+
+  /* Actually sprintf the values in place
+   *  (+ 2 skips the ", " for first value) */
+  if (n_coords > 1)
+    g_string_append_c (buff, '(');
+  if (suffix_type == FILE_MODE)
+    {
+      g_ascii_formatd (filemode_buff, sizeof filemode_buff, printf_buff + 2, value[0]);
+      g_string_append_printf (buff, "%s", filemode_buff);
+    }
+  else
+    g_string_append_printf (buff, printf_buff + 2, value[0]);
+  for (i = 1; i < n_coords; ++i)
+    {
+      if (suffix_type == FILE_MODE)
+        {
+          g_ascii_formatd (filemode_buff, sizeof filemode_buff, printf_buff, value[i]);
+          g_string_append_printf (buff, "%s", filemode_buff);
+        }
+      else
+        g_string_append_printf (buff, printf_buff, value[i]);
+    }
+  if (n_coords > 1)
+    g_string_append_c (buff, ')');
+  /* Append suffix */
+  if (value[0] != 0 || n_coords > 1)
+    {
+      switch (suffix_type)
+        {
+        case NO_SUFFIX:
+          break;
+        case SUFFIX:
+          g_string_append_printf (buff, " %s", suffix);
+          break;
+        case FILE_MODE:
+          g_string_append_printf (buff, "%s", suffix);
+          break;
+        }
+    }
+
+  g_free (printf_buff);
+  free (value);
+  /* Return just the gchar* part of our string */
+  return g_string_free (buff, FALSE);
+}
+
+static gchar *pcb_vprintf(const char *fmt, va_list args)
+{
+  GString *string = g_string_new ("");
+  GString *spec   = g_string_new ("");
+
+  if (string == NULL || spec == NULL)
+    return NULL;
+
+  while(*fmt)
+    {
+      enum e_suffix suffix = NO_SUFFIX;
+      int multiplier = 0;
+
+      if(*fmt == '%')
+        {
+          gchar *unit_str = NULL;
+          const char *ext_unit = "";
+          BDimension value[10];
+          int count, i;
+
+          g_string_assign (spec, "");
+
+          /* Get printf sub-specifiers */
+          g_string_append_c (spec, *fmt++);
+          while(isdigit(*fmt) || *fmt == '.' || *fmt == ' ' || *fmt == '*'
+                              || *fmt == '#' || *fmt == 'l' || *fmt == 'L'
+                              || *fmt == 'h' || *fmt == '-')
+            g_string_append_c (spec, *fmt++);
+          /* Get our sub-specifiers */
+          if(*fmt == ':')
+            {
+              multiplier = strtol(fmt + 1, (char **)&fmt, 0);
+            }
+          if(*fmt == '$')
+            {
+              suffix = SUFFIX;
+              fmt++;
+            }
+          /* Tack full specifier onto specifier */
+          if (*fmt != 'm')
+            g_string_append_c (spec, *fmt);
+          switch(*fmt)
+            {
+            /* Printf specs */
+            case 'o': case 'i': case 'd':
+            case 'u': case 'x': case 'X':
+              if(spec->str[1] == 'l')
+                {
+                  if(spec->str[2] == 'l')
+                    unit_str = g_strdup_printf (spec->str, va_arg(args, long long));
+                  else
+                    unit_str = g_strdup_printf (spec->str, va_arg(args, long));
+                }
+              else
+                {
+                  unit_str = g_strdup_printf (spec->str, va_arg(args, int));
+                }
+              break;
+            case 'e': case 'E': case 'f':
+            case 'g': case 'G':
+              if (strchr (spec->str, '*'))
+                unit_str = g_strdup_printf (spec->str, va_arg(args, double));
+              else
+                unit_str = g_strdup_printf (spec->str, va_arg(args, double), va_arg(args, int));
+              break;
+            case 'c':
+              if(spec->str[1] == 'l' && sizeof(int) <= sizeof(wchar_t))
+                unit_str = g_strdup_printf (spec->str, va_arg(args, wchar_t));
+              else
+                unit_str = g_strdup_printf (spec->str, va_arg(args, int));
+              break;
+            case 's':
+              if(spec->str[0] == 'l')
+                unit_str = g_strdup_printf (spec->str, va_arg(args, wchar_t *));
+              else
+                unit_str = g_strdup_printf (spec->str, va_arg(args, char *));
+              break;
+            case 'n':
+              /* Depending on gcc settings, this will probably break with
+               *  some silly "can't put %n in writeable data space" message */
+              unit_str = g_strdup_printf (spec->str, va_arg(args, int *));
+              break;
+            case 'p':
+              unit_str = g_strdup_printf (spec->str, va_arg(args, void *));
+              break;
+            case '%':
+              g_string_append_c (string, '%');
+              break;
+            /* Our specs */
+            case 'm':
+              ++fmt;
+              if (*fmt == '*')
+                ext_unit = va_arg(args, const char *);
+              value[0] = va_arg(args, BDimension);
+              count = 1;
+              switch(*fmt)
+                {
+                case 's': unit_str = CoordsToString(value, 1, spec->str, ALLOW_MM | ALLOW_MIL, suffix); break;
+                case 'S': unit_str = CoordsToString(value, 1, spec->str, ALLOW_ALL, suffix); break;
+                case 'M': unit_str = CoordsToString(value, 1, spec->str, ALLOW_METRIC, suffix); break;
+                case 'L': unit_str = CoordsToString(value, 1, spec->str, ALLOW_IMPERIAL, suffix); break;
+                case 'r': unit_str = CoordsToString(value, 1, spec->str, ALLOW_READABLE, FILE_MODE); break;
+                /* All these fallthroughs are deliberate */
+                case '9': value[count++] = va_arg(args, BDimension);
+                case '8': value[count++] = va_arg(args, BDimension);
+                case '7': value[count++] = va_arg(args, BDimension);
+                case '6': value[count++] = va_arg(args, BDimension);
+                case '5': value[count++] = va_arg(args, BDimension);
+                case '4': value[count++] = va_arg(args, BDimension);
+                case '3': value[count++] = va_arg(args, BDimension);
+                case '2':
+                case 'D':
+                  value[count++] = va_arg(args, BDimension);
+                  unit_str = CoordsToString(value, count, spec->str, ALLOW_ALL, suffix);
+                  break;
+                case 'd':
+                  value[1] = va_arg(args, BDimension);
+                  unit_str = CoordsToString(value, 2, spec->str, ALLOW_MM | ALLOW_MIL, suffix);
+                  break;
+                case '*':
+                  for (i = 0; i < N_UNITS; ++i)
+                    if (strcmp (ext_unit, Units[i].suffix) == 0)
+                      unit_str = CoordsToString(value, 1, spec->str, Units[i].allow, suffix);
+                  if (unit_str == NULL)
+                    unit_str = CoordsToString(value, 1, spec->str, ALLOW_ALL, suffix);
+                  break;
+                default:
+                  for (i = 0; i < N_UNITS; ++i)
+                    if (*fmt == Units[i].printf_code)
+                      unit_str = CoordsToString(value, 1, spec->str, Units[i].allow, suffix);
+                  if (unit_str == NULL)
+                    unit_str = CoordsToString(value, 1, spec->str, ALLOW_ALL, suffix);
+                  break;
+                }
+              break;
+            }
+          if (unit_str != NULL)
+            {
+              g_string_append (string, unit_str);
+              g_free (unit_str);
+            }
+        }
+      else
+        g_string_append_c (string, *fmt);
+      ++fmt;
+    }
+  g_string_free (spec, TRUE);
+  /* Return just the gchar* part of our string */
+  return g_string_free (string, FALSE);
+}
+
+
+int pcb_sprintf(char *string, const char *fmt, ...)
+{
+  gchar *tmp;
+
+  va_list args;
+  va_start(args, fmt);
+
+  tmp = pcb_vprintf (fmt, args);
+  strcpy (string, tmp);
+  g_free (tmp);
+  
+  va_end(args);
+  return strlen (string);
+}
+
+int pcb_fprintf(FILE *fh, const char *fmt, ...)
+{
+  int rv;
+  gchar *tmp;
+
+  va_list args;
+  va_start(args, fmt);
+
+  tmp = pcb_vprintf (fmt, args);
+  rv = fprintf (fh, "%s", tmp);
+  g_free (tmp);
+  
+  va_end(args);
+  return rv;
+}
+
+char *pcb_g_strdup_printf(const char *fmt, ...)
+{
+  gchar *tmp;
+
+  va_list args;
+  va_start(args, fmt);
+  tmp = pcb_vprintf (fmt, args);
+  va_end(args);
+  return tmp;
+}
+
diff --git a/src/pcb-printf.h b/src/pcb-printf.h
new file mode 100644
index 0000000..2c11b8f
--- /dev/null
+++ b/src/pcb-printf.h
@@ -0,0 +1,93 @@
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 2011 Andrew Poelstra
+ *
+ *  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 2 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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Andrew Poelstra, 16966 60A Ave, V3S 8X5 Surrey, BC, Canada
+ *  asp11@xxxxxx
+ *
+ */
+
+/* This file defines a wrapper around sprintf, that
+ *  defines new specifiers that take pcb BDimension
+ *  objects as input.
+ *
+ * There is a fair bit of nasty (repetitious) code in
+ *  here, but I feel the gain in clarity for output
+ *  code elsewhere in the project will make it worth
+ *  it.
+ *
+ * The new specifiers are:
+ *   %mm    output a measure in mm
+ *   %mM    output a measure in scaled (mm/um) metric
+ *   %ml    output a measure in mil
+ *   %mL    output a measure in scaled (mil/in) imperial
+ *   %ms    output a measure in most natural mm/mil units
+ *   %mS    output a measure in most natural scaled units
+ *   %md    output a pair of measures in most natural mm/mil units
+ *   %mD    output a pair of measures in most natural scaled units
+ *   %m3    output 3 measures in most natural scaled units
+ *     ...
+ *   %m9    output 9 measures in most natural scaled units
+ *   %m*    output a measure with unit given as an additional
+ *          const char* parameter
+ *   %mr    output a measure in a unit readable by parse_l.l
+ *          (this will always append a unit suffix)
+ *
+ * These accept the usual printf modifiers for %f,
+ *  as well as the additional modifier $ which is
+ *  used to output a unit suffix after the measure.
+ *
+ * KNOWN ISSUES:
+ *   No support for %zu size_t printf spec
+ *   No support for .* subspecifier for pcb specs
+ */
+
+#ifndef	__PCB_PRINTF_INCLUDED__
+#define	__PCB_PRINTF_INCLUDED__
+
+enum e_allow {
+  ALLOW_NM = 1,
+  ALLOW_UM = 2,
+  ALLOW_MM = 4,
+  ALLOW_CM = 8,
+  ALLOW_M  = 16,
+  ALLOW_KM = 32,
+
+  ALLOW_CMIL = 1024,
+  ALLOW_MIL  = 2048,
+  ALLOW_IN   = 4096,
+
+  ALLOW_METRIC   = ALLOW_NM | ALLOW_UM | ALLOW_MM |
+                   ALLOW_CM | ALLOW_M  | ALLOW_KM,
+  ALLOW_IMPERIAL = ALLOW_CMIL | ALLOW_MIL | ALLOW_IN,
+  /* This is all units allowed in parse_l.l */
+  ALLOW_READABLE = ALLOW_NM | ALLOW_UM | ALLOW_MM |
+                   ALLOW_M  | ALLOW_KM | ALLOW_CMIL |
+                   ALLOW_MIL | ALLOW_IN,
+
+  ALLOW_ALL = ~0
+};
+
+int pcb_fprintf(FILE *f, const char *fmt, ...);
+int pcb_sprintf(char *string, const char *fmt, ...);
+char *pcb_g_strdup_printf(const char *fmt, ...);
+
+#endif
+




_______________________________________________
geda-cvs mailing list
geda-cvs@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-cvs