| /* |
| * Copyright 2001-2004 Brandon Long |
| * All Rights Reserved. |
| * |
| * ClearSilver Templating System |
| * |
| * This code is made available under the terms of the ClearSilver License. |
| * http://www.clearsilver.net/license.hdf |
| * |
| */ |
| |
| #ifndef __NEO_HDF_H_ |
| #define __NEO_HDF_H_ 1 |
| |
| __BEGIN_DECLS |
| |
| #include <stdio.h> |
| #include "util/neo_err.h" |
| #include "util/neo_hash.h" |
| |
| #define FORCE_HASH_AT 10 |
| |
| typedef struct _hdf HDF; |
| |
| /* HDFFILELOAD is a callback function to intercept file load requests and |
| * provide templates via another mechanism. This way you can load templates |
| * that you compiled-into your binary, from in-memory caches, or from a |
| * zip file, etc. The HDF is provided so you can choose to use the |
| * hdf_search_path function to find the file. contents should return |
| * a full malloc copy of the contents of the file, which the parser will |
| * own and free. Use hdf_register_fileload to set this function for |
| * your top level HDF node. |
| * NOTE: Technically, we shouldn't need a separate copy for each parse, but |
| * using the separate copy makes this equivalent to the CSFILELOAD function. We |
| * can change this if we really want to save that copy at the expense of |
| * slightly more complicated code. */ |
| typedef NEOERR* (*HDFFILELOAD)(void *ctx, HDF *hdf, const char *filename, |
| char **contents); |
| |
| typedef struct _attr |
| { |
| char *key; |
| char *value; |
| struct _attr *next; |
| } HDF_ATTR; |
| |
| struct _hdf |
| { |
| int link; |
| int alloc_value; |
| char *name; |
| int name_len; |
| char *value; |
| struct _attr *attr; |
| struct _hdf *top; |
| struct _hdf *next; |
| struct _hdf *child; |
| |
| /* the following fields are used to implement a cache */ |
| struct _hdf *last_hp; |
| struct _hdf *last_hs; |
| |
| /* the following HASH is used when we reach more than FORCE_HASH_AT |
| * elements */ |
| NE_HASH *hash; |
| /* When using the HASH, we need to know where to append new children */ |
| struct _hdf *last_child; |
| |
| /* Should only be set on the head node, used to override the default file |
| * load method */ |
| void *fileload_ctx; |
| HDFFILELOAD fileload; |
| }; |
| |
| /* |
| * Function: hdf_init - Initialize an HDF data set |
| * Description: hdf_init initializes an HDF data set and returns the |
| * pointer to the top node in the data set. |
| * Input: hdf - pointer to an HDF pointer |
| * Output: hdf - allocated hdf node |
| * Returns: NERR_NOMEM - unable to allocate memory for dataset |
| */ |
| NEOERR* hdf_init (HDF **hdf); |
| |
| /* |
| * Function: hdf_destroy - deallocate an HDF data set |
| * Description: hdf_destroy is used to deallocate all memory associated |
| * with an hdf data set. Although you can pass an HDF node |
| * as an argument to this function, you are likely to cause |
| * a segfault if you continue to access the data set. In |
| * the future, we may restrict hdf_destroy so it only works |
| * on the top level node. |
| * Input: hdf - pointer to an HDF data set allocated with hdf_init |
| * Output: None |
| * Returns: None |
| */ |
| void hdf_destroy (HDF **hdf); |
| |
| /* |
| * Function: hdf_get_int_value - Return the integer value of a point in |
| * the data set |
| * Description: hdf_get_int_value walks the HDF data set pointed to by |
| * hdf to name, and returns the value of that node |
| * converted to an integer. If that node does not exist, |
| * or it does not contain a number, the defval is returned. |
| * Input: hdf -> a node in an HDF data set |
| * name -> the name of a node to walk to in the data set |
| * defval -> value to return in case of error or if the node |
| * doesn't exist |
| * Output: None |
| * Returns: The integer value of the node, or the defval |
| */ |
| int hdf_get_int_value (HDF *hdf, const char *name, int defval); |
| |
| /* |
| * Function: hdf_get_value - Return the value of a node in the data set |
| * Description: hdf_get_value walks the data set pointed to by hdf via |
| * name and returns the string value located there, or |
| * defval if the node doesn't exist |
| * Input: hdf -> the dataset node to start from |
| * name -> the name to walk the data set to |
| * defval -> the default value to return if the node doesn't |
| * exist |
| * Output: None |
| * Returns: A pointer to the string stored in the data set, or defval. |
| * The data set maintains ownership of the string, if you want |
| * a copy you either have to call strdup yourself, or use |
| * hdf_get_copy |
| */ |
| char *hdf_get_value (HDF *hdf, const char *name, const char *defval); |
| |
| /* |
| * Function: hdf_get_valuevf - Return the value of a node in the data set |
| * Description: hdf_get_valuevf walks the data set pointed to by hdf via |
| * namefmt printf expanded with varargs ap, and returns the |
| * string value located there, or NULL if it doesn't exist. |
| * This differs from hdf_get_value in that there is no |
| * default value possible. |
| * Input: hdf -> the dataset node to start from |
| * namefmt -> the format string |
| * ap -> va_list of varargs |
| * Output: None |
| * Returns: A pointer to the string stored in the data set, or NULL. |
| * The data set maintains ownership of the string, if you want |
| * a copy you either have to call strdup yourself. |
| */ |
| char* hdf_get_valuevf (HDF *hdf, const char *namefmt, va_list ap); |
| |
| /* |
| * Function: hdf_get_valuef - Return the value of a node in the data set |
| * Description: hdf_get_valuef walks the data set pointed to by hdf via |
| * namefmt printf expanded with varargs, and returns the |
| * string value located there, or NULL if it doesn't exist. |
| * This differs from hdf_get_value in that there is no |
| * default value possible. |
| * Input: hdf -> the dataset node to start from |
| * namefmt -> the printf-style format string |
| * ... -> arguments to fill out namefmt |
| * Output: None |
| * Returns: A pointer to the string stored in the data set, or NULL. |
| * The data set maintains ownership of the string, if you want |
| * a copy you either have to call strdup yourself. |
| */ |
| char* hdf_get_valuef (HDF *hdf, const char *namefmt, ...) |
| ATTRIBUTE_PRINTF(2,3); |
| |
| /* |
| * Function: hdf_get_copy - Returns a copy of a string in the HDF data set |
| * Description: hdf_get_copy is similar to hdf_get_value, except that it |
| * returns an malloc'd copy of the string. |
| * Input: hdf -> the dataset node to start from |
| * name -> the name to walk the data set to |
| * defval -> the default value to return if the node doesn't |
| * exist |
| * Output: value -> the allocated string (if defval = NULL, then value |
| * will be NULL if defval is used) |
| * Returns: NERR_NOMEM if unable to allocate the new copy |
| */ |
| NEOERR* hdf_get_copy (HDF *hdf, const char *name, char **value, |
| const char *defval); |
| |
| /* |
| * Function: hdf_get_obj - return the HDF data set node at a named location |
| * Description: hdf_get_obj walks the dataset given by hdf to the node |
| * named name, and then returns the pointer to that node |
| * Input: hdf -> the dataset node to start from |
| * name -> the name to walk to |
| * Output: None |
| * Returns: the pointer to the named node, or NULL if it doesn't exist |
| */ |
| HDF* hdf_get_obj (HDF *hdf, const char *name); |
| |
| /* |
| * Function: hdf_get_node - Similar to hdf_get_obj except all the nodes |
| * are created if the don't exist. |
| * Description: hdf_get_node is similar to hdf_get_obj, except instead |
| * of stopping if it can't find a node in the tree, it will |
| * create all of the nodes necessary to hand you back the |
| * node you ask for. Nodes are created with no value. |
| * Input: hdf -> the dataset node to start from |
| * name -> the name to walk to |
| * Output: ret -> the dataset node you asked for |
| * Returns: NERR_NOMEM - unable to allocate new nodes |
| */ |
| NEOERR * hdf_get_node (HDF *hdf, const char *name, HDF **ret); |
| |
| /* |
| * Function: hdf_get_child - return the first child of the named node |
| * Description: hdf_get_child will walk the dataset starting at hdf to |
| * name, and return the first child of that node |
| * Input: hdf -> the dataset node to start from |
| * name -> the name to walk to |
| * Output: None |
| * Returns: The first child of the named dataset node or NULL if the |
| * node is not found (or it has no children) |
| */ |
| HDF* hdf_get_child (HDF *hdf, const char *name); |
| |
| /* |
| * Function: hdf_get_attr - |
| * Description: |
| * Input: |
| * Output: |
| * Returns: |
| */ |
| HDF_ATTR* hdf_get_attr (HDF *hdf, const char *name); |
| |
| /* |
| * Function: hdf_set_attr - |
| * Description: |
| * Input: |
| * Output: |
| * Returns: |
| */ |
| NEOERR* hdf_set_attr (HDF *hdf, const char *name, const char *key, |
| const char *value); |
| |
| /* |
| * Function: hdf_obj_child - Return the first child of a dataset node |
| * Description: hdf_obj_child and the other hdf_obj_ functions are |
| * accessors to the HDF dataset. Although we do not |
| * currently "hide" the HDF struct implementation, we |
| * recommend you use the accessor functions instead of |
| * accessing the values directly. |
| * Input: hdf -> the hdf dataset node |
| * Output: None |
| * Returns: The pointer to the first child, or NULL if there is none |
| */ |
| HDF* hdf_obj_child (HDF *hdf); |
| |
| /* |
| * Function: hdf_obj_next - Return the next node of a dataset level |
| * Description: hdf_obj_next is an accessor function for the HDF struct |
| * Input: hdf -> the hdf dataset node |
| * Output: None |
| * Returns: The pointer to the next node, or NULL if there is none |
| */ |
| HDF* hdf_obj_next (HDF *hdf); |
| |
| /* |
| * Function: hdf_obj_top - Return the pointer to the top dataset node |
| * Description: hdf_obj_top is an accessor function which returns a |
| * pointer to the top of the dataset, the node which was |
| * returned by hdf_init. This is most useful for |
| * implementations of language wrappers where individual |
| * nodes are tied garbage colletion wise to the top node of |
| * the data set |
| * Input: hdf -> the hdf dataset node |
| * Output: None |
| * Returns: The pointer to the top node |
| */ |
| HDF* hdf_obj_top (HDF *hdf); |
| |
| /* |
| * Function: hdf_obj_attr - Return the HDF Attributes for a node |
| * Description: |
| * Input: |
| * Output: |
| * Returns: |
| */ |
| HDF_ATTR* hdf_obj_attr (HDF *hdf); |
| |
| /* |
| * Function: hdf_obj_name - Return the name of a node |
| * Description: hdf_obj_name is an accessor function for a datset node |
| * which returns the name of the node. This is just the |
| * local name, and not the full path. |
| * Input: hdf -> the hdf dataset node |
| * Output: None |
| * Returns: The name of the node. If this is the top node, the name is |
| * NULL. |
| */ |
| char* hdf_obj_name (HDF *hdf); |
| |
| /* |
| * Function: hdf_obj_value - Return the value of a node |
| * Description: hdf_obj_value is an accessor function for a dataset node |
| * which returns the value of the node, or NULL if the node |
| * has no value. This is not a copy of the value, so the |
| * node retains ownership of the value |
| * Input: hdf -> the hdf dataset node |
| * Output: None |
| * Returns: The value of the node, or NULL if it has no value |
| */ |
| char* hdf_obj_value (HDF *hdf); |
| |
| /* |
| * Function: hdf_set_value - Set the value of a named node |
| * Description: hdf_set_value will set the value of a named node. All |
| * of the interstitial nodes which don't exist will be |
| * created with a value of NULL. Existing nodes are not |
| * modified. New nodes are created at the end of the list. |
| * If a list of nodes exceeds FORCE_HASH_AT, then a HASH |
| * will be created at that level and all of the nodes will |
| * be added to the hash for faster lookup times. |
| * The copy of the value will be made which the dataset |
| * will own. |
| * Input: hdf -> the pointer to the hdf dataset |
| * name -> the named node to walk to |
| * value -> the value to set the node to |
| * Output: None |
| * Returns: NERR_NOMEM |
| */ |
| NEOERR* hdf_set_value (HDF *hdf, const char *name, const char *value); |
| |
| /* |
| * Function: hdf_set_valuef - Set the value of a named node |
| * Description: hdf_set_valuef is a convenience function that wraps |
| * hdf_set_value. Due to limitations of C, the fmt is in |
| * the format "name=value", where we will first format the |
| * entire string, and then break it at the first (from the |
| * left) equal sign (=) and use the left portion as the |
| * name and the right portion as the value. This function |
| * is somewhat inefficient in that it first allocates the |
| * full name=value, and then the call to hdf_set_value |
| * duplicates the value portion, and then we free the |
| * name=value. |
| * Currently, we don't strip whitespace from the key or |
| * value. In the future, this function might work more |
| * like reading a single line of an HDF string or file, |
| * allowing for attributes and symlinks to be specified... |
| * maybe. |
| * Input: hdf -> the pointer to the hdf dataset |
| * fmt -> the name=value printf(3) format string |
| * Output: None |
| * Returns: NERR_NOMEM |
| */ |
| NEOERR* hdf_set_valuef (HDF *hdf, const char *fmt, ...) |
| ATTRIBUTE_PRINTF(2,3); |
| NEOERR* hdf_set_valuevf (HDF *hdf, const char *fmt, va_list ap); |
| |
| /* |
| * Function: hdf_set_int_value - Set the value of a named node to a number |
| * Description: hdf_set_int_value is a helper function that maps an |
| * integer to a string, and then calls hdf_set_value with |
| * that string |
| * Input: hdf -> the pointer to the hdf dataset |
| * name -> the named node to walk to |
| * value -> the value to set the node to |
| * Output: None |
| * Returns: NERR_NOMEM |
| */ |
| NEOERR* hdf_set_int_value (HDF *hdf, const char *name, int value); |
| |
| /* |
| * Function: hdf_set_copy -> Copy a value from one location in the |
| * dataset to another |
| * Description: hdf_set_copy first walks the hdf dataset to the named src |
| * node, and then copies that value to the named dest node. |
| * If the src node is not found, an error is raised. |
| * Input: hdf -> the pointer to the dataset node |
| * dest -> the name of the destination node |
| * src -> the name of the source node |
| * Output: None |
| * Returns: NERR_NOMEM, NERR_NOT_FOUND |
| */ |
| NEOERR* hdf_set_copy (HDF *hdf, const char *dest, const char *src); |
| |
| /* |
| * Function: hdf_set_buf - Set the value of a node without duplicating |
| * the value |
| * Description: hdf_set_buf is similar to hdf_set_value, except the |
| * dataset takes ownership of the value instead of making a |
| * copy of it. The dataset assumes that value was |
| * malloc'd, since it will attempt to free it when |
| * hdf_destroy is called |
| * Input: hdf -> the hdf dataset node |
| * name -> the name to walk to |
| * value -> the malloc'd value |
| * Output: None |
| * Returns: NERR_NOMEM - unable to allocate a node |
| */ |
| |
| NEOERR* hdf_set_buf (HDF *hdf, const char *name, char *value); |
| |
| /* |
| * Function: hdf_set_symlink - Set part of the tree to link to another |
| * Description: hdf_set_symlink creates a link between two sections of |
| * an HDF dataset. The link is "by name" hence the term |
| * "symlink". This means that the destination node does |
| * not need to exist. Any attempt to access the source |
| * node will cause the function to walk to the dest node, |
| * and then continue walking from there. Using symlinks |
| * can "hide" values in the dataset since you won't be able |
| * to access any children of the linked node directly, |
| * though dumps and other things which access the data |
| * structure directly will bypass the symlink. Use this |
| * feature sparingly as its likely to surprise you. |
| * Input: hdf -> the dataset node |
| * src -> the source node name |
| * dest -> the destination node name (from the top of the |
| * dataset, not relative names) |
| * Output: None |
| * Returns: NERR_NOMEM |
| */ |
| NEOERR *hdf_set_symlink (HDF *hdf, const char *src, const char *dest); |
| |
| /* |
| * Function: hdf_sort_obj - sort the children of an HDF node |
| * Description: hdf_sort_obj will sort the children of an HDF node, |
| * based on the given comparison function. |
| * This function works by creating an array of the pointers |
| * for each child object of h, using qsort to sort that |
| * array, and then re-ordering the linked list of children |
| * to the new order. The qsort compare function uses a |
| * pointer to the value in the array, which in our case is |
| * a pointer to an HDF struct, so your comparison function |
| * should work on HDF ** pointers. |
| * Input: h - HDF node |
| * compareFunc - function which returns 1,0,-1 depending on some |
| * criteria. The arguments to this sort function |
| * are pointers to pointers to HDF elements. For |
| * example: |
| * int sortByName(const void *a, const void *b) { |
| * HDF **ha = (HDF **)a; |
| * HDF **hb = (HDF **)b; |
| * |
| * return strcasecmp(hdf_obj_name(*ha), hdf_obj_name(*hb)); |
| * } |
| * |
| * Output: None (h children will be sorted) |
| * Return: NERR_NOMEM |
| */ |
| NEOERR *hdf_sort_obj(HDF *h, int (*compareFunc)(const void *, const void *)); |
| |
| /* |
| * Function: hdf_read_file - read an HDF data file |
| * Description: |
| * Input: |
| * Output: |
| * Returns: NERR_IO, NERR_NOMEM, NERR_PARSE |
| */ |
| NEOERR* hdf_read_file (HDF *hdf, const char *path); |
| |
| /* |
| * Function: hdf_write_file - write an HDF data file |
| * Description: |
| * Input: |
| * Output: |
| * Returns: NERR_IO |
| */ |
| NEOERR* hdf_write_file (HDF *hdf, const char *path); |
| |
| /* |
| * Function: hdf_write_file_atomic - write an HDF data file atomically |
| * Description: hdf_write_file_atomic is similar to hdf_write_file, |
| * except the new file is created with a unique name and |
| * then rename(2) is used to atomically replace the old |
| * file with the new file |
| * Input: |
| * Output: |
| * Returns: NERR_IO |
| */ |
| NEOERR* hdf_write_file_atomic (HDF *hdf, const char *path); |
| |
| /* |
| * Function: hdf_read_string - read an HDF string |
| * Description: |
| * Input: |
| * Output: |
| * Returns: NERR_NOMEM, NERR_PARSE |
| */ |
| NEOERR* hdf_read_string (HDF *hdf, const char *s); |
| |
| /* |
| * Function: hdf_read_string_ignore - Read an HDF string and ignore errors |
| * Description: |
| * Input: |
| * Output: |
| * Returns: NERR_NOMEM |
| */ |
| NEOERR* hdf_read_string_ignore (HDF *hdf, const char *s, int ignore); |
| |
| /* |
| * Function: hdf_write_string - serialize an HDF dataset to a string |
| * Description: |
| * Input: |
| * Output: |
| * Returns: NERR_NOMEM |
| */ |
| NEOERR* hdf_write_string (HDF *hdf, char **s); |
| |
| /* |
| * Function: hdf_dump - dump an HDF dataset to stdout |
| * Description: |
| * Input: |
| * Output: |
| * Returns: |
| */ |
| NEOERR* hdf_dump (HDF *hdf, const char *prefix); |
| |
| /* |
| * Function: hdf_dump_format - dump an HDF dataset to FILE *fp |
| * Description: |
| * Input: |
| * Output: |
| * Returns: |
| */ |
| NEOERR* hdf_dump_format (HDF *hdf, int lvl, FILE *fp); |
| |
| /* |
| * Function: hdf_dump_str - dump an HDF dataset to STRING |
| * Description: |
| * Input: |
| * Output: |
| * Returns: |
| */ |
| NEOERR* hdf_dump_str(HDF *hdf, const char *prefix, int compact, STRING *str); |
| |
| /* |
| * Function: hdf_remove_tree - delete a subtree of an HDF dataset |
| * Description: |
| * Input: |
| * Output: |
| * Returns: |
| */ |
| NEOERR* hdf_remove_tree (HDF *hdf, const char *name); |
| |
| /* |
| * Function: hdf_copy - copy part of an HDF dataset to another |
| * Description: hdf_copy is a deep copy of an HDF tree pointed to by |
| * src to the named node of dest. dest and src need not be |
| * part of the same data set |
| * Input: dest_hdf -> the destination dataset |
| * name -> the name of the destination node |
| * src -> the hdf dataset to copy to the destination |
| * Output: None |
| * Returns: NERR_NOMEM, NERR_NOT_FOUND |
| */ |
| NEOERR* hdf_copy (HDF *dest_hdf, const char *name, HDF *src); |
| |
| /* |
| * Function: hdf_search_path - Find a file given a search path in HDF |
| * Description: hdf_search_path is a convenience/utility function that |
| * searches for relative filenames in a search path. The |
| * search path is the list given by the children of |
| * hdf.loadpaths. |
| * Input: hdf -> the hdf dataset to use |
| * path -> the relative path |
| * full -> a pointer to a _POSIX_PATH_MAX buffer |
| * Output: full -> the full path of the file |
| * Returns: NERR_NOT_FOUND if the file wasn't found in the search path |
| */ |
| NEOERR* hdf_search_path (HDF *hdf, const char *path, char *full); |
| |
| /* |
| * Function: hdf_register_fileload - register a fileload function |
| * Description: hdf_register_fileload registers a fileload function that |
| * overrides the built-in function. The built-in function |
| * uses hdf_search_path and ne_file_load (based on stat/open/read) |
| * to find and load the file on every hdf_read_file (including |
| * #include). You can override this function if you wish to provide |
| * other file search functions, or load the hdf file |
| * from an in-memory cache, etc. |
| * Input: hdf - pointer to a head HDF node |
| * ctx - pointer that is passed to the HDFFILELOAD function when called |
| * fileload - a HDFFILELOAD function |
| * Output: None |
| * Return: None |
| * |
| */ |
| |
| void hdf_register_fileload(HDF *hdf, void *ctx, HDFFILELOAD fileload); |
| |
| __END_DECLS |
| |
| #endif /* __NEO_HDF_H_ */ |