Logo Search packages:      
Sourcecode: libnih version File versions  Download package

type.c

/* nih-dbus-tool
 *
 * type.c - type handling
 *
 * Copyright © 2009 Scott James Remnant <scott@netsplit.com>.
 * Copyright © 2009 Canonical Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2, as
 * published by the Free Software Foundation.
 *
 * 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.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */


#include <dbus/dbus.h>

#include <string.h>

#include <nih/macros.h>
#include <nih/alloc.h>
#include <nih/list.h>
#include <nih/string.h>
#include <nih/logging.h>

#include "symbol.h"
#include "indent.h"
#include "type.h"


/**
 * type_const:
 * @dbus_type: D-Bus type constant.
 *
 * Converts an integer D-Bus type constant into the string name of the
 * constant, used when generating code.
 *
 * Returns: constant string.
 **/
const char *
type_const (int dbus_type)
{
      switch (dbus_type) {
      case DBUS_TYPE_BYTE:
            return "DBUS_TYPE_BYTE";
      case DBUS_TYPE_BOOLEAN:
            return "DBUS_TYPE_BOOLEAN";
      case DBUS_TYPE_INT16:
            return "DBUS_TYPE_INT16";
      case DBUS_TYPE_UINT16:
            return "DBUS_TYPE_UINT16";
      case DBUS_TYPE_INT32:
            return "DBUS_TYPE_INT32";
      case DBUS_TYPE_UINT32:
            return "DBUS_TYPE_UINT32";
      case DBUS_TYPE_INT64:
            return "DBUS_TYPE_INT64";
      case DBUS_TYPE_UINT64:
            return "DBUS_TYPE_UINT64";
      case DBUS_TYPE_DOUBLE:
            return "DBUS_TYPE_DOUBLE";
      case DBUS_TYPE_STRING:
            return "DBUS_TYPE_STRING";
      case DBUS_TYPE_OBJECT_PATH:
            return "DBUS_TYPE_OBJECT_PATH";
      case DBUS_TYPE_SIGNATURE:
            return "DBUS_TYPE_SIGNATURE";
      case DBUS_TYPE_ARRAY:
            return "DBUS_TYPE_ARRAY";
      case DBUS_TYPE_STRUCT:
            return "DBUS_TYPE_STRUCT";
      case DBUS_TYPE_DICT_ENTRY:
            return "DBUS_TYPE_DICT_ENTRY";
      default:
            nih_assert_not_reached ();
      }
}


/**
 * type_of:
 * @parent: parent object for new string,
 * @iter: D-Bus signature iterator.
 *
 * Converts the D-Bus basic type at the current element of the iterator
 * @iter into an appropriate C type to hold it.
 *
 * If @parent is not NULL, it should be a pointer to another object which
 * will be used as a parent for the returned string.  When all parents
 * of the returned string are freed, the returned string will also be
 * freed.
 *
 * Returns: newly allocated string or NULL if allocation failed.
 **/
char *
type_of (const void *       parent,
       DBusSignatureIter *iter)
{
      int dbus_type;

      nih_assert (iter != NULL);

      dbus_type = dbus_signature_iter_get_current_type (iter);

      switch (dbus_type) {
      case DBUS_TYPE_BYTE:
            return nih_strdup (parent, "uint8_t");
      case DBUS_TYPE_BOOLEAN:
            return nih_strdup (parent, "int");
      case DBUS_TYPE_INT16:
            return nih_strdup (parent, "int16_t");
      case DBUS_TYPE_UINT16:
            return nih_strdup (parent, "uint16_t");
      case DBUS_TYPE_INT32:
            return nih_strdup (parent, "int32_t");
      case DBUS_TYPE_UINT32:
            return nih_strdup (parent, "uint32_t");
      case DBUS_TYPE_INT64:
            return nih_strdup (parent, "int64_t");
      case DBUS_TYPE_UINT64:
            return nih_strdup (parent, "uint64_t");
      case DBUS_TYPE_DOUBLE:
            return nih_strdup (parent, "double");
      case DBUS_TYPE_STRING:
            return nih_strdup (parent, "char *");
      case DBUS_TYPE_OBJECT_PATH:
            return nih_strdup (parent, "char *");
      case DBUS_TYPE_SIGNATURE:
            return nih_strdup (parent, "char *");
      default:
            nih_assert_not_reached ();
      }
}


/**
 * type_var_new:
 * @parent: parent object for new structure,
 * @type: C type,
 * @name: variable name.
 *
 * Allocates and returns a new TypeVar structure with the C type @type
 * and variable name @name, the strucure is not placed into any linked
 * list but will be removed from its containing list when freed.
 *
 * If @parent is not NULL, it should be a pointer to another object which
 * will be used as a parent for the returned structure.  When all parents
 * of the returned structure are freed, the returned structure will also be
 * freed.
 *
 * Returns: the new TypeVar structure or NULL if insufficient memory.
 **/
TypeVar *
type_var_new (const void *parent,
            const char *type,
            const char *name)
{
      TypeVar *var;

      nih_assert (type != NULL);
      nih_assert (name != NULL);

      var = nih_new (parent, TypeVar);
      if (! var)
            return NULL;

      nih_list_init (&var->entry);

      var->type = nih_strdup (var, type);
      if (! var->type) {
            nih_free (var);
            return NULL;
      }

      var->name = nih_strdup (var, name);
      if (! var->name) {
            nih_free (var);
            return NULL;
      }

      var->array = FALSE;

      nih_alloc_set_destructor (var, nih_list_destroy);

      return var;
}

/**
 * type_var_to_string:
 * @parent: parent object for new string,
 * @var: variable to convert.
 *
 * Returns a string for the given variable @var, consisting of the type
 * and variable name separated by a space if appropriate.
 *
 * If @parent is not NULL, it should be a pointer to another object which
 * will be used as a parent for the returned string.  When all parents
 * of the returned string are freed, the returned string will also be
 * freed.
 *
 * Returns: the newly allocated string or NULL if insufficient memory.
 **/
char *
type_var_to_string (const void *parent,
                TypeVar *   var)
{
      char *str;

      nih_assert (var != NULL);

      if (strchr (var->type, '*')) {
            str = nih_sprintf (parent, "%s%s", var->type, var->name);
      } else {
            str = nih_sprintf (parent, "%s %s", var->type, var->name);
      }

      if (! str)
            return NULL;

      if (var->array) {
            if (! nih_strcat (&str, parent, "[]")) {
                  nih_free (str);
                  return NULL;
            }
      }

      return str;
}

/**
 * type_var_layout:
 * @parent: parent object for new string,
 * @vars: list of variables to convert.
 *
 * Returns a string for the list of variables @vars, each of which should
 * be a TypeVar structure.  Each variable is declared on a new line,
 * with the names lined up to the longest type length.
 *
 * If @parent is not NULL, it should be a pointer to another object which
 * will be used as a parent for the returned string.  When all parents
 * of the returned string are freed, the returned string will also be
 * freed.
 *
 * Returns: the newly allocated string or NULL if insufficient memory.
 **/
char *
type_var_layout (const void *parent,
             NihList *   vars)
{
      size_t max;
      size_t len;
      char * str;

      nih_assert (vars != NULL);

      /* Work out how much space to have for the types */
      max = 0;
      NIH_LIST_FOREACH (vars, iter) {
            TypeVar *var = (TypeVar *)iter;
            size_t   this_len;

            this_len = strlen (var->type);
            if (! strchr (var->type, '*'))
                  this_len++;

            if (this_len > max)
                  max = this_len;
      }

      /* Allocate a string with each of the variables on each line. */
      len = 0;
      str = nih_strdup (parent, "");
      if (! str)
            return NULL;

      NIH_LIST_FOREACH (vars, iter) {
            TypeVar *var = (TypeVar *)iter;
            char *   new_str;

            new_str = nih_realloc (str, parent,
                               (len + max + strlen (var->name)
                              + (var->array ? 2 : 0) + 3));
            if (! new_str) {
                  nih_free (str);
                  return NULL;
            }

            str = new_str;

            memset (str + len, ' ', max);
            memcpy (str + len, var->type, strlen (var->type));
            len += max;

            memcpy (str + len, var->name, strlen (var->name));
            len += strlen (var->name);

            if (var->array) {
                  memcpy (str + len, "[]", 2);
                  len += 2;
            }

            memcpy (str + len, ";\n", 2);
            len += 2;

            str[len] = '\0';
      }

      return str;
}


/**
 * type_func_new:
 * @parent: parent object for new structure,
 * @type: C return type,
 * @name: function name.
 *
 * Allocates and returns a new TypeFunc structure with the
 * C return type @type and function name @name, the structure is not placed
 * into any linked list but will be removed from its containing list when
 * freed.
 *
 * If @parent is not NULL, it should be a pointer to another object which
 * will be used as a parent for the returned structure.  When all parents
 * of the returned structure are freed, the returned structure will also be
 * freed.
 *
 * Returns: the new TypeFunc structure or NULL if insufficient memory.
 **/
TypeFunc *
type_func_new (const void *parent,
             const char *type,
             const char *name)
{
      TypeFunc *func;

      nih_assert (type != NULL);
      nih_assert (name != NULL);

      func = nih_new (parent, TypeFunc);
      if (! func)
            return NULL;

      nih_list_init (&func->entry);

      func->type = nih_strdup (func, type);
      if (! func->type) {
            nih_free (func);
            return NULL;
      }

      func->name = nih_strdup (func, name);
      if (! func->name) {
            nih_free (func);
            return NULL;
      }

      nih_list_init (&func->args);
      nih_list_init (&func->attribs);

      nih_alloc_set_destructor (func, nih_list_destroy);

      return func;
}

/**
 * type_func_to_string:
 * @parent: parent object for new string,
 * @func: function to convert.
 *
 * Returns a string for the given function @func for use as the function
 * declaration header.
 *
 * If @parent is not NULL, it should be a pointer to another object which
 * will be used as a parent for the returned string.  When all parents
 * of the returned string are freed, the returned string will also be
 * freed.
 *
 * Returns: the newly allocated string or NULL if insufficient memory.
 **/
char *
type_func_to_string (const void *parent,
                 TypeFunc *  func)
{
      char * str;
      size_t max;
      size_t len;

      nih_assert (func != NULL);

      /* Type goes on a separate line to the name */
      str = nih_sprintf (parent, "%s\n%s (", func->type, func->name);
      if (! str)
            return NULL;

      /* If no arguments, should be just void */
      if (NIH_LIST_EMPTY (&func->args)) {
            if (! nih_strcat (&str, parent, "void)\n")) {
                  nih_free (str);
                  return NULL;
            }

            return str;
      }

      /* Figure out the longest type name */
      max = 0;
      NIH_LIST_FOREACH (&func->args, iter) {
            TypeVar *arg = (TypeVar *)iter;
            size_t   this_len;

            this_len = strlen (arg->type);
            if (! strchr (arg->type, '*'))
                  this_len++;

            if (this_len > max)
                  max = this_len;
      }

      /* Append each argument with all the types and names lined up */
      len = strlen (str);
      NIH_LIST_FOREACH (&func->args, iter) {
            TypeVar *arg = (TypeVar *)iter;
            char *   new_str;

            /* Each additional argument goes onto a new line, indented
             * by the length of the function name plus the usual
             * punctuation
             */
            if (iter != func->args.next) {
                  new_str = nih_realloc (str, parent,
                                     len + strlen (func->name) + 5);
                  if (! new_str) {
                        nih_free (str);
                        return NULL;
                  }

                  str = new_str;

                  memcpy (str + len, ",\n", 2);
                  len += 2;

                  memset (str + len, ' ', strlen (func->name) + 2);
                  len += strlen (func->name) + 2;

                  str[len] = '\0';
            }

            /* Append the argument so that the names line up */
            new_str = nih_realloc (str, parent,
                               len + max + strlen (arg->name) + 1);
            if (! new_str) {
                  nih_free (str);
                  return NULL;
            }

            str = new_str;

            memset (str + len, ' ', max);
            memcpy (str + len, arg->type, strlen (arg->type));
            len += max;

            memcpy (str + len, arg->name, strlen (arg->name));
            len += strlen (arg->name);

            str[len] = '\0';
      }

      if (! nih_strcat (&str, parent, ")\n")) {
            nih_free (str);
            return NULL;
      }

      return str;
}

/**
 * type_func_to_typedef:
 * @parent: parent object for new string,
 * @func: function to convert.
 *
 * Returns a string for the given function typedef @func for use as the
 * typedef declaration.
 *
 * If @parent is not NULL, it should be a pointer to another object which
 * will be used as a parent for the returned string.  When all parents
 * of the returned string are freed, the returned string will also be
 * freed.
 *
 * Returns: the newly allocated string or NULL if insufficient memory.
 **/
char *
type_func_to_typedef (const void *parent,
                  TypeFunc *  func)
{
      char *str;

      nih_assert (func != NULL);

      str = nih_sprintf (parent, "%s %s (", func->type, func->name);
      if (! str)
            return NULL;

      /* If no arguments, should be just void */
      if (NIH_LIST_EMPTY (&func->args)) {
            if (! nih_strcat (&str, parent, "void")) {
                  nih_free (str);
                  return NULL;
            }
      }

      /* Append the arguments */
      NIH_LIST_FOREACH (&func->args, iter) {
            TypeVar *       arg = (TypeVar *)iter;
            nih_local char *arg_str = NULL;

            if (iter != func->args.next) {
                  if (! nih_strcat (&str, parent, ", ")) {
                        nih_free (str);
                        return NULL;
                  }
            }

            arg_str = type_var_to_string (NULL, arg);
            if (! arg_str) {
                  nih_free (str);
                  return NULL;
            }

            if (! nih_strcat (&str, parent, arg_str)) {
                  nih_free (str);
                  return NULL;
            }
      }

      if (! nih_strcat (&str, parent, ");\n")) {
            nih_free (str);
            return NULL;
      }

      return str;
}

/**
 * type_func_layout:
 * @parent: parent object for new string,
 * @funcs: list of functions to convert.
 *
 * Returns a string for the list of functions @funcs, each of which should
 * be a TypeFunc structure.  Each function is declared on a new line,
 * with the names lined up to the longest type length and the arguments
 * list lined up to the longest name length.  Attributes follow on the next
 * line.
 *
 * If @parent is not NULL, it should be a pointer to another object which
 * will be used as a parent for the returned string.  When all parents
 * of the returned string are freed, the returned string will also be
 * freed.
 *
 * Returns: the newly allocated string or NULL if insufficient memory.
 **/
char *
type_func_layout (const void *parent,
              NihList *   funcs)
{
      size_t type_max;
      size_t name_max;
      char * str;

      nih_assert (funcs != NULL);

      /* Work out how much space to have for the types and the names */
      type_max = 0;
      name_max = 0;
      NIH_LIST_FOREACH (funcs, iter) {
            TypeFunc *func = (TypeFunc *)iter;
            size_t    this_type_len;
            size_t    this_name_len;

            this_type_len = strlen (func->type);
            if (! strchr (func->type, '*'))
                  this_type_len++;

            this_name_len = strlen (func->name);

            if (this_type_len > type_max)
                  type_max = this_type_len;
            if (this_name_len > name_max)
                  name_max = this_name_len;
      }

      /* Allocate a string with each of the functions on each line. */
      str = nih_strdup (parent, "");
      if (! str)
            return NULL;

      NIH_LIST_FOREACH (funcs, iter) {
            TypeFunc *func = (TypeFunc *)iter;
            char *    new_str;
            size_t    len;

            len = strlen (str);

            new_str = nih_realloc (str, parent,
                               len + type_max + name_max + 3);
            if (! new_str) {
                  nih_free (str);
                  return NULL;
            }

            str = new_str;

            memset (str + len, ' ', type_max);
            memcpy (str + len, func->type, strlen (func->type));
            len += type_max;

            memset (str + len, ' ', name_max + 1);
            memcpy (str + len, func->name, strlen (func->name));
            len += name_max + 1;

            str[len] = '(';
            len++;

            str[len] = '\0';

            /* If no arguments, should be just void */
            if (NIH_LIST_EMPTY (&func->args)) {
                  if (! nih_strcat (&str, parent, "void")) {
                        nih_free (str);
                        return NULL;
                  }
            }

            /* Append the arguments */
            NIH_LIST_FOREACH (&func->args, iter) {
                  TypeVar *       arg = (TypeVar *)iter;
                  nih_local char *arg_str = NULL;

                  if (iter != func->args.next) {
                        if (! nih_strcat (&str, parent, ", ")) {
                              nih_free (str);
                              return NULL;
                        }
                  }

                  arg_str = type_var_to_string (NULL, arg);
                  if (! arg_str) {
                        nih_free (str);
                        return NULL;
                  }

                  if (! nih_strcat (&str, parent, arg_str)) {
                        nih_free (str);
                        return NULL;
                  }
            }

            /* If there are no attributes, that's it */
            if (NIH_LIST_EMPTY (&func->attribs)) {
                  if (! nih_strcat (&str, parent, ");\n")) {
                        nih_free (str);
                        return NULL;
                  }

                  continue;
            }

            /* Append the attributes indented on the next line */
            if (! nih_strcat (&str, parent, ")\n\t__attribute__ ((")) {
                  nih_free (str);
                  return NULL;
            }

            NIH_LIST_FOREACH (&func->attribs, iter) {
                  NihListEntry *attrib = (NihListEntry *)iter;

                  if (iter != func->attribs.next) {
                        if (! nih_strcat (&str, parent, ", ")) {
                              nih_free (str);
                              return NULL;
                        }
                  }

                  if (! nih_strcat (&str, parent, attrib->str)) {
                        nih_free (str);
                        return NULL;
                  }
            }

            if (! nih_strcat (&str, parent, "));\n")) {
                  nih_free (str);
                  return NULL;
            }
      }

      return str;
}


/**
 * type_struct_new:
 * @parent: parent object for new structure,
 * @name: structure name.
 *
 * Allocates and returns a new TypeStruct structure with the structure
 * name @name, the structure is not placed into any linked list but will
 * be removed from its containing list when freed.
 *
 * If @parent is not NULL, it should be a pointer to another object which
 * will be used as a parent for the returned structure.  When all parents
 * of the returned structure are freed, the returned structure will also be
 * freed.
 *
 * Returns: the new TypeStruct structure or NULL if insufficient memory.
 **/
TypeStruct *
type_struct_new (const void *parent,
             const char *name)
{
      TypeStruct *structure;

      nih_assert (name != NULL);

      structure = nih_new (parent, TypeStruct);
      if (! structure)
            return NULL;

      nih_list_init (&structure->entry);

      structure->name = nih_strdup (structure, name);
      if (! structure->name) {
            nih_free (structure);
            return NULL;
      }

      nih_list_init (&structure->members);

      nih_alloc_set_destructor (structure, nih_list_destroy);

      return structure;
}

/**
 * type_struct_to_string:
 * @parent: parent object for new string,
 * @structure: structure to convert.
 *
 * Returns a string for the given @structure declaring it both as a C
 * structure and as a shorter typedef.
 *
 * If @parent is not NULL, it should be a pointer to another object which
 * will be used as a parent for the returned string.  When all parents
 * of the returned string are freed, the returned string will also be
 * freed.
 *
 * Returns: the newly allocated string or NULL if insufficient memory.
 **/
char *
type_struct_to_string (const void *parent,
                   TypeStruct *structure)
{
      nih_local char *symbol = NULL;
      nih_local char *block = NULL;
      char *          str;

      nih_assert (structure != NULL);

      /* Generate a lowercase structure symbol */
      symbol = symbol_from_name (NULL, structure->name);
      if (! symbol)
            return NULL;

      /* Line up the members and indent */
      block = type_var_layout (NULL, &structure->members);
      if (! block)
            return NULL;

      if (! NIH_LIST_EMPTY (&structure->members))
            if (! indent (&block, NULL, 1))
                  return NULL;

      /* Output */
      str = nih_sprintf (parent,
                     "typedef struct %s {\n"
                     "%s"
                     "} %s;\n",
                     symbol,
                     block,
                     structure->name);

      return str;
}


/**
 * type_to_const:
 * @type: C type,
 * @parent: parent object for original string.
 *
 * Converts the C type @type into a constant form if it's a pointer type.
 *
 * Only the first level of pointer is made constant, this is consistent
 * with C99 only allowing one level of type-compatibility in this regard.
 * i.e.:
 *   char * becomes const char *
 *   char ** becomes char * const *
 *
 * This has no effect if the first level of pointer is already constant,
 * if other levels are constant, the pointer will become more constant.
 *
 * @type is modified directly, the returned string is simply a pointer to
 * it, thus @parent is actually ignored though it usual to pass the parent
 * of @type for style reasons.
 *
 * Returns: modified @type or NULL if insufficient memory.
 **/
char *
type_to_const (char **     type,
             const void *parent)
{
      char * ptr;
      char * ret;
      size_t len;

      nih_assert (type != NULL);
      nih_assert (*type != NULL);

      len = strlen (*type);
      nih_assert (len > 0);

      /* If this is a pointer, the final character will be the operator;
       * if not, we can return now.
       */
      ptr = *type + len - 1;
      if (*ptr != '*')
            return *type;

      /* Check whether this is the sole pointer operator, if not we need
       * to insert "const" before this one - otherwise we simply prepend
       * the declaration with "const".  In both cases, check it's not
       * already there.  (This still allows us to const-up a pointer).
       */
      if (strchr (*type, '*') != ptr) {
            if ((len > 8)
                && (! strncmp (*type + len - 8, " const *", 8)))
                  return *type;

            ret = nih_realloc (*type, parent, len + 8);
            if (! ret)
                  return NULL;

            *type = ret;

            memcpy (*type + len - 1, " const *", 9);
      } else if (strncmp (*type, "const ", 6)) {
            ret = nih_realloc (*type, parent, len + 7);
            if (! ret)
                  return NULL;

            *type = ret;
            memmove (*type + 6, *type, len + 1);
            memcpy (*type, "const ", 6);
      }

      return *type;
}

/**
 * type_to_pointer:
 * @type: C type,
 * @parent: parent object for original string.
 *
 * Covnerts the C type @type into a type containing a pointer to the
 * original type.  If the type in @type is already a pointer, a further
 * level of indirection is added.
 *
 * This has a special behaviour in the case of constant pointers, the
 * constantness is moved from the previous top level to the new top
 * level.
 * i.e.:
 *   const char * becomes char * const *
 *   char * const * becomes char ** const *
 *
 * This is to allow for arrays to pointerify their elements whilst
 * preserving the "I don't modify this" flag use of const.  We can't
 * just add another const becuse C99 only allows one level of
 * type-compatibility.
 *
 * @type is modified directly, the returned string is simply a pointer to
 * it, thus @parent is actually ignored though it usual to pass the parent
 * of @type for style reasons.
 *
 * Returns: modified @type or NULL if insufficient memory.
 **/
char *
type_to_pointer (char **     type,
             const void *parent)
{
      char *  ptr;
      char *  ret;
      size_t len;

      nih_assert (type != NULL);
      nih_assert (*type != NULL);

      len = strlen (*type);
      nih_assert (len > 0);

      ptr = *type + len - 1;

      /* If the string is a single-level constant pointer, we have to
       * shuffle it all around to make it a two-level pointer with the
       * new first-level constant.
       *
       * If the string is a nth-level constant pointer, we just insert
       * a pointer in before the const part.
       *
       * If the string is any kind of pointer, we append another pointer.
       *
       * Otherwise we add a pointer and a space to keep everything
       * separate.
       */
      if ((strchr (*type, '*') == ptr)
          && (! strncmp (*type, "const ", 6))) {
            ret = nih_realloc (*type, parent, len + 3);
            if (! ret)
                  return NULL;

            *type = ret;

            memmove (*type, *type + 6, len - 6);
            memcpy (*type + len - 6, " const *", 9);

      } else if ((len > 8)
               && (! strncmp (*type + len - 8, " const *", 8))) {
            ret = nih_realloc (*type, parent, len + 2);
            if (! ret)
                  return NULL;

            *type = ret;

            memcpy (*type + len - 8, "* const *", 10);
      } else if (*ptr == '*') {
            ret = nih_realloc (*type, parent, len + 2);
            if (! ret)
                  return NULL;

            *type = ret;

            memcpy (*type + len, "*", 2);
      } else {
            ret = nih_realloc (*type, parent, len + 3);
            if (! ret)
                  return NULL;

            *type = ret;

            memcpy (*type + len, " *", 3);
      }

      return *type;
}

/**
 * type_to_static:
 * @type: C type,
 * @parent: parent object for original string.
 *
 * Converts the C type @type into a static form.
 *
 * This has no effect if the type is already static.
 *
 * @type is modified directly, the returned string is simply a pointer to
 * it, thus @parent is actually ignored though it usual to pass the parent
 * of @type for style reasons.
 *
 * Returns: modified @type or NULL if insufficient memory.
 **/
char *
type_to_static (char **     type,
            const void *parent)
{
      char * ret;
      size_t len;

      nih_assert (type != NULL);
      nih_assert (*type != NULL);

      len = strlen (*type);
      nih_assert (len > 0);

      if (strncmp (*type, "static ", 7)) {
            ret = nih_realloc (*type, parent, len + 8);
            if (! ret)
                  return NULL;

            *type = ret;

            memmove (*type + 7, *type, len + 1);
            memcpy (*type, "static ", 7);
      }

      return *type;
}

/**
 * type_to_extern:
 * @type: C type,
 * @parent: parent object for original string.
 *
 * Converts the C type @type into an extern form.
 *
 * This has no effect if the type is already extern.
 *
 * @type is modified directly, the returned string is simply a pointer to
 * it, thus @parent is actually ignored though it usual to pass the parent
 * of @type for style reasons.
 *
 * Returns: modified @type or NULL if insufficient memory.
 **/
char *
type_to_extern (char **     type,
            const void *parent)
{
      char * ret;
      size_t len;

      nih_assert (type != NULL);
      nih_assert (*type != NULL);

      len = strlen (*type);
      nih_assert (len > 0);

      if (strncmp (*type, "extern ", 7)) {
            ret = nih_realloc (*type, parent, len + 8);
            if (! ret)
                  return NULL;

            *type = ret;

            memmove (*type + 7, *type, len + 1);
            memcpy (*type, "extern ", 7);
      }

      return *type;
}


/**
 * type_strcat_assert:
 * @block: code block to append to,
 * @parent: parent object for @block,
 * @var: variable to append assert block for,
 * @prev: prev variable in list or NULL,
 * @next: next variable in list or NULL.
 *
 * If @var is a pointer variable, appends a line of code to @block that
 * asserts that the variable is not NULL.  If @var is not a pointer variable,
 * this function has no effect.
 *
 * This function handles the case of @var being an array and @next
 * being its size member, in which case @var may be NULL if its size member
 * is zero.
 *
 * This function also handles the case of @var being an array of size
 * members and @prev being the array, in which case @var may be NULL if the
 * first member of @prev is NULL.
 *
 * @block is modified directly, the returned string is simply a pointer to
 * it, thus @parent is actually ignored though it usual to pass the parent
 * of @block for style reasons.
 *
 * Note that @block may be returned unmodified, therefore it is not
 * permitted to pass NULL for @block as this would be indistinguishable from
 * insufficient memory.
 *
 * Returns: modified @block or NULL if insufficient memory.
 **/
char *
type_strcat_assert (char **     block,
                const void *parent,
                TypeVar *   var,
                TypeVar *   prev,
                TypeVar *   next)
{
      nih_assert (block != NULL);
      nih_assert (var != NULL);

      if (! strchr (var->type, '*'))
            return *block;

      if (next && (! strcmp (next->type, "size_t"))) {
            if (! nih_strcat_sprintf (block, parent,
                                "nih_assert ((%s == 0) || (%s != NULL));\n",
                                next->name, var->name))
                  return NULL;

      } else if (prev && strstr (var->type, "size_t")) {
            if (! nih_strcat_sprintf (block, parent,
                                "nih_assert ((*%s == NULL) || (%s != NULL));\n",
                                prev->name, var->name))
                  return NULL;

      } else {
            if (! nih_strcat_sprintf (block, parent,
                                "nih_assert (%s != NULL);\n",
                                var->name))
                  return NULL;
      }

      return *block;
}


Generated by  Doxygen 1.6.0   Back to index