/* * The Npic library * * Copyright (C) 2003 Edouard Thiel * * This library is free software under the terms of the * GNU Lesser General Public License (LGPL) version 2.1. */ /* * props.c - 02/03/2007 * * Manage text properties for images and masks */ #include #define NPIC_PROPS_STEP 32 /*--------------------- P U B L I C - I N T E R F A C E ----------------------*/ /* * Initialize Npic_props structure. Silent. */ void NpicInitProps (Npic_props *props) { if (props == NULL) return; props->nb = 0; props->tot = 0; props->list = NULL; } /* * Free Npic_props structure. Silent. */ void NpicFreeProps (Npic_props *props) { int i; if (props == NULL) return; if (props->list != NULL) { for (i = 0; i < props->nb; i++) { free (props->list[i].key); free (props->list[i].val); } free (props->list); } NpicInitProps (props); } /* * Copy properties from src to dest ; free dest before if non empty. * On success return NPIC_SUCCESS, else error code. Silent. */ int NpicCopyProps (Npic_props *dest, Npic_props *src) { int i, k; if (dest == NULL || src == NULL) return NPIC_ERR_NULL_PTR; NpicFreeProps (dest); for (i = 0; i < src->nb; i++) { k = NpicAddProp (dest, src->list[i].key, src->list[i].val); if (k != NPIC_SUCCESS) return k; } return NPIC_SUCCESS; } /* * Test if a key is valid. Return 1 if valid, else 0. Silent. * * A key is said valid if it is a non-empty string only composed * of chars in [33,126] and different from ':'. * In particular, chars '\t', ' ' and '\n' are forbidden. */ int NpicPropKeyIsValid (const char *key) { int i; if (key == NULL || key[0] == 0) return 0; for (i = 0; key[i] ; i++) if (key[i] <= 32 || key[i] >= 127 || key[i] == ':') return 0; return 1; } /* * Test if a val is valid. Return 1 if valid, else 0. Silent. * * A val is said valid if it is a possibly empty string only composed * of chars in [32,126] or a '\t'. * In particular, char '\n' is forbidden, ' ' and ':' are allowed. */ int NpicPropValIsValid (const char *val) { int i; if (val == NULL) return 0; for (i = 0; val[i] ; i++) if ((val[i] < 32 || val[i] >= 127) && val[i] != '\t') return 0; return 1; } /* * Insert a property (key, val) in properties list (only if key and val * are valid, else they are rejected). * If key is already in list, the val is overwritten. * The list is sorted by key, to allow fast dichotomic search. * The list is enlarged if necessary. * On success return NPIC_SUCCESS, else error code. Verbose. */ int NpicAddProp (Npic_props *props, const char *key, const char *val) { int k, ind; char *dup_key, *dup_val; if (props == NULL || key == NULL || val == NULL) return NPIC_ERR_NULL_PTR; /* Check if key and val are valid */ if (NpicPropKeyIsValid (key) == 0) return NpicError (__func__, NPIC_ERROR, ": bad key \"%s\" for property", key); if (NpicPropValIsValid (val) == 0) return NpicError (__func__, NPIC_ERROR, ": bad value \"%s\" for property", val); /* Search key */ k = NpicPropSearch (props, key, &ind); /* Key found, overwrite val */ if (k == 0) { dup_val = strdup (val); if (dup_val == NULL) return NpicError (__func__, NPIC_ERR_STRDUP, ""); free (props->list[ind].val); props->list[ind].val = dup_val; return NPIC_SUCCESS; } /* Enlarge list if necessary */ if (props->nb >= props->tot) { int tot = props->tot + NPIC_PROPS_STEP, als = tot * sizeof (Npic_atom); Npic_atom *tmp; if (props->list == NULL) tmp = malloc (als); else tmp = realloc (props->list, als); if (tmp == NULL) return NpicError (__func__, NPIC_ERR_REALLOC, ""); props->list = tmp; props->tot = tot; } /* Duplicate now key and val, to be sure we won't insert a hole */ dup_key = strdup (key); dup_val = strdup (val); if (dup_key == NULL || dup_val == NULL) { free (dup_key); free (dup_val); return NpicError (__func__, NPIC_ERR_STRDUP, ""); } /* Shift list[ind..nb[ to the right */ if (ind < props->nb) memmove ( props->list + (ind+1), props->list + ind, sizeof (Npic_atom) * (props->nb - ind) ); /* Insert (key, val) at position ind */ props->list[ind].key = dup_key; props->list[ind].val = dup_val; props->nb++; return NPIC_SUCCESS; } /* * Remove a property (key, val) from properties list. * The list is kept sorted, without hole. * The list is shortened if necessary. * On success return NPIC_SUCCESS, else error code. Verbose. */ int NpicSupprProp (Npic_props *props, const char *key) { int k, ind; if (props == NULL || key == NULL) return NPIC_ERR_NULL_PTR; if (key[0] == 0) return NPIC_ERR_EMPTY_STR; k = NpicPropSearch (props, key, &ind); /* Key not found (silent) */ if (k != 0) return NPIC_ERR_NOT_FOUND; /* Suppress (key, val) from position ind */ if (props->list[ind].key != NULL) free (props->list[ind].key); if (props->list[ind].val != NULL) free (props->list[ind].val); /* Shift list[ind+1..nb[ to the left */ if (ind < props->nb-1) memmove ( props->list + ind, props->list + (ind+1), sizeof (Npic_atom) * (props->nb-1 - ind) ); props->nb--; /* Shorten list if necessary */ if (props->tot - props->nb > 2*NPIC_PROPS_STEP) { int tot = props->tot - NPIC_PROPS_STEP, als = tot * sizeof (Npic_atom); Npic_atom *tmp; tmp = realloc (props->list, als); if (tmp == NULL) return NpicError (__func__, NPIC_ERR_REALLOC, ""); props->list = tmp; props->tot = tot; } return NPIC_SUCCESS; } /* * Search a property from its key. * Return property value if found, else default_val. Silent. * To know if a property is set, use NpicHasProp. */ const char *NpicGetPropD (Npic_props *props, const char *key, const char *default_val) { int k, ind; if (props == NULL || key == NULL || key[0] == 0) return ""; k = NpicPropSearch (props, key, &ind); return k == 0 ? props->list[ind].val : default_val; } /* Same as NpigGetPropD; return property value if found, else "". */ const char *NpicGetProp (Npic_props *props, const char *key) { return NpicGetPropD (props, key, ""); } /* * Search a property from its key. * Return 1 if found, else 0. Silent. */ int NpicHasProp (Npic_props *props, const char *key) { int ind; if (props == NULL || key == NULL || key[0] == 0) return 0; return NpicPropSearch (props, key, &ind) == 0 ? 1 : 0; } /* * Print all properties. */ void NpicPrintProps (Npic_props *props) { int i; if (props == NULL) return; printf ("Number of properties: %d\n", props->nb); printf ("Properties: i \"key\" \"val\"\n"); for (i = 0; i < props->nb; i++) printf ("%3d \"%s\" \"%s\"\n", i, props->list[i].key, props->list[i].val); } /*-------------------- P R I V A T E - F U N C T I O N S ---------------------*/ /* * Dichotomic search of key. * If found, return 0 and ret_index contains the index; * If not, return -1 and ret_index contains the insertion position. */ int NpicPropSearch (Npic_props *props, const char *key, int *ret_index) { int m1 = 0, m2 = props->nb, mid = 0, res = 0; char *s; while (m2-m1 > 0) { mid = (m1+m2) / 2; s = props->list[mid].key; /* Paranoia test for strcmp, the list should not have holes */ if (s == NULL) { *ret_index = props->nb; return -1; } /* Error */ res = strcmp (key, s); if (res < 0) m2 = mid; else if (res > 0) m1 = mid+1; else { *ret_index = mid; return 0; } /* Found */ } *ret_index = (res > 0) ? mid+1 : mid; /* Not found */ return -1; } /* * Read a line "key: val\n" in f, and store the property in props. * The line is not limited in size. * * If line is not a property : * - NPIC_ERROR will be returned, * - if keep_line is non-NULL, *keep_line will contain the line. * Thus, if keep_line is non-NULL, free *keep_line after usage. * * Return NPIC_SUCCESS, else error code. Silent. */ int NpicPropRead (Npic_props *props, FILE *f, char **keep_line) { int c, nb = 0, tot = 0, step = 4096, colon = -1, res; char *buf = NULL, *tmp; if (keep_line) *keep_line = NULL; while ((c = fgetc (f)) != EOF && c != '\n') { /* Enlarge buf if necessary */ if (nb >= tot-1) { if (buf == NULL) tmp = malloc (step); else tmp = realloc (buf, tot+step); if (tmp == NULL) { free (buf); return NPIC_ERR_REALLOC; } tot += step; buf = tmp; } /* Find the first ':' */ if (c == ':' && colon == -1) colon = nb; /* Store c */ buf[nb] = c; nb++; } if (buf == NULL) return NPIC_ERR_REALLOC; buf[nb] = 0; /* This line is not a property; we save buf in keep_line */ if (colon == -1 || buf[colon+1] != ' ') { if (keep_line) *keep_line = buf; else free (buf); return NPIC_ERROR; } buf[colon] = 0; res = NpicAddProp (props, buf, buf+colon+2); free (buf); return res; } /*----------------------------------------------------------------------------*/