manual: Add short option example.
[adu.git] / format.c
index 3d1daa2..94315e9 100644 (file)
--- a/format.c
+++ b/format.c
@@ -1,10 +1,10 @@
 /*
- * Copyright (C) 2008 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2008 Andre Noll <maan@tuebingen.mpg.de>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
 
-/** \file format.c Functions for pretty-printing numbers and strings. */
+/** \file format.c \brief Functions for pretty-printing numbers and strings. */
 
 #include <dirent.h> /* readdir() */
 #include "adu.h"
 #include "string.h"
 #include "error.h"
 #include "format.h"
+
+/** The three different alignment types. */
 enum alignment {ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER};
 
 struct num_format {
        enum alignment align;
        char unit;
-       int supress_unit;
+       int suppress_unit;
 };
 
 struct string_format {
@@ -95,12 +97,12 @@ static struct format_item *make_const_string(char *cp, char *ep)
        return fi;
 }
 
-static struct format_item *parse_atom(char *ap, struct atom *atoms)
+static int parse_atom(char *ap, struct atom *atoms, struct format_item **result)
 {
        struct format_item *fi = NULL;
        int i, n, len;
        char *col, *ep = strchr(ap, ')');
-       char *err_msg = "malformed format string";
+       int ret = -E_MALFORMED_FORMAT;
 
        if (!ep)
                goto err;
@@ -127,17 +129,17 @@ static struct format_item *parse_atom(char *ap, struct atom *atoms)
                case AT_ID:
                        fi->af.nf.align = ALIGN_RIGHT;
                        fi->af.nf.unit = ' ';
-                       fi->af.nf.supress_unit = 0;
+                       fi->af.nf.suppress_unit = 0;
                        break;
                case AT_COUNT:
                        fi->af.nf.align = ALIGN_RIGHT;
                        fi->af.nf.unit = 'H';
-                       fi->af.nf.supress_unit = 0;
+                       fi->af.nf.suppress_unit = 0;
                        break;
                case AT_SIZE:
                        fi->af.nf.align = ALIGN_RIGHT;
                        fi->af.nf.unit = 'h';
-                       fi->af.nf.supress_unit = 0;
+                       fi->af.nf.suppress_unit = 0;
                        break;
                }
                if (!col)
@@ -157,7 +159,7 @@ static struct format_item *parse_atom(char *ap, struct atom *atoms)
                        col--;
                        break;
                default:
-                       err_msg = "bad alignment spec";
+                       ret = -E_BAD_ALIGN_SPEC;
                        goto err;
                }
                switch (col[2]) {
@@ -167,7 +169,7 @@ static struct format_item *parse_atom(char *ap, struct atom *atoms)
                        col += 2;
                        break;
                default:
-                       err_msg = "trailing garbage after alignment spec";
+                       ret = -E_TRAILING_GARBAGE;
                        goto err;
                }
                /* read width */
@@ -181,15 +183,15 @@ static struct format_item *parse_atom(char *ap, struct atom *atoms)
                        col += 1 + n;
                        break;
                default:
-                       err_msg = "trailing garbage after width spec";
+                       ret = -E_TRAILING_GARBAGE;
                        goto err;
                }
                if (a->type != AT_SIZE && a->type != AT_COUNT) {
-                       err_msg = "no unit allowed here";
+                       ret = -E_UNIT;
                        goto err;
                }
                if (col[1] == '*') {
-                       fi->af.nf.supress_unit = 1;
+                       fi->af.nf.suppress_unit = 1;
                        col++;
                }
                for (j = 0; units[j]; j++) {
@@ -199,28 +201,37 @@ static struct format_item *parse_atom(char *ap, struct atom *atoms)
                        break;
                }
                if (!units[j]) {
-                       err_msg = "bad unit spec";
+                       ret = -E_BAD_UNIT;
                        goto err;
                }
                if (col + 2 != ep) {
-                       err_msg = "trailing garbage after unit spec";
+                       ret = -E_TRAILING_GARBAGE;
                        goto err;
                }
                goto success;
        }
-       err_msg = "invalid atom";
+       ret = -E_BAD_ATOM;
 err:
-       ERROR_LOG("%s\n", err_msg);
        free(fi);
-       return NULL;
+       return ret;
 success:
-       return fi;
+       *result = fi;
+       return 1;
 }
 
-struct format_info *parse_format_string(char *fmt, struct atom *atoms)
+/**
+ * Parse the given string according to the list of given atoms.
+ *
+ * \param fmt The format string.
+ * \param atoms The array of valid atoms.
+ * \param result Points to a format_info structure for later use.
+ *
+ * \return Standard.
+ */
+int parse_format_string(char *fmt, struct atom *atoms, struct format_info **result)
 {
        char *cp, *ap, *ep;
-       int num_items;
+       int num_items, ret;
        struct format_info *info = malloc(sizeof(*info));
 
        info->atoms = atoms;
@@ -234,8 +245,8 @@ struct format_info *parse_format_string(char *fmt, struct atom *atoms)
                        num_items++;
                }
                info->items = realloc(info->items, (num_items + 1) * sizeof(struct format_info *));
-               info->items[num_items] = parse_atom(ap + 2, atoms);
-               if (!info->items[num_items]) {
+               ret = parse_atom(ap + 2, atoms, info->items + num_items);
+               if (ret < 0) {
                        num_items--;
                        goto err;
                }
@@ -249,7 +260,8 @@ struct format_info *parse_format_string(char *fmt, struct atom *atoms)
        }
        info->items = realloc(info->items, (num_items + 1) * sizeof(struct format_info *));
        info->items[num_items] = NULL;
-       return info;
+       *result = info;
+       return 1;
 err:
        for (; num_items >= 0; num_items--) {
                if (!info->items[num_items]->atom_ptr)
@@ -258,14 +270,26 @@ err:
        }
        free(info->items);
        free(info);
-       return NULL;
+       *result = NULL;
+       return ret;
 }
 
+/**
+ * Free a struct of type \a format_info.
+ *
+ * \param info Pointer to the format info to be freed.
+ *
+ * It's OK to pass a \p NULL pointer to this function in which case the
+ * function does nothing.
+ */
 void free_format_info(struct format_info *info)
 {
        int i;
        struct format_item *item;
 
+       if (!info)
+               return;
+
        for (i = 0; (item = info->items[i]); i++) {
                if (!item->atom_ptr)
                        free(item->af.cs.string);
@@ -351,7 +375,7 @@ static long long unsigned normalize_number(long long unsigned num, char unit,
 static void get_unit_postfix(struct num_format *nf, char eu, enum atom_type type,
                char postfix[2])
 {
-       if (nf->supress_unit) {
+       if (nf->suppress_unit) {
                *postfix = '\0';
                return;
        }
@@ -389,11 +413,21 @@ static char *align_unsigned_int(long long unsigned num, unsigned int width,
                nnum, postfix, width - (width + len) / 2, "");
 }
 
+/**
+ * Pretty-format the given values according to \a info.
+ *
+ * \param info The formating information.
+ * \param values The contents of the atoms.
+ *
+ * \return A string that must be freed by the caller.
+ */
 char *format_items(struct format_info *info, union atom_value *values)
 {
        int i;
        char *buf = NULL;
 
+       if (!info)
+               return NULL;
        for (i = 0; info->items[i]; i++) {
                struct atom *a;
                struct format_item *fi = info->items[i];
@@ -415,13 +449,14 @@ char *format_items(struct format_info *info, union atom_value *values)
                        align = af->sf.align;
                        val = align_string(values[idx].string_value, fi->width, align);
                } else {
-                       char unit;
                        align = af->nf.align;
-                       unit = af->nf.unit;
                        val = align_unsigned_int(values[idx].num_value,
                                fi->width, &af->nf, type);
                }
                buf = adu_strcat(buf, val);
+               free(val);
        }
+       if (!buf)
+               buf = adu_strdup("");
        return buf;
 }