QOF 0.8.2
|
Files | |
file | qofutil.h |
QOF utility functions. | |
Defines | |
#define | QOF_MOD_UTIL "qof-utilities" |
#define | stpcpy g_stpcpy |
omitted if stpcpy exists. | |
#define | CACHE_INSERT(str) qof_util_string_cache_insert((gconstpointer)(str)) |
#define | CACHE_REMOVE(str) qof_util_string_cache_remove((str)) |
#define | CACHE_REPLACE(dst, src) |
#define | QOF_CACHE_NEW(void) qof_util_string_cache_insert("") |
Functions | |
gint | safe_strcmp (const gchar *da, const gchar *db) |
gint | safe_strcasecmp (const gchar *da, const gchar *db) |
gint | null_strcmp (const gchar *da, const gchar *db) |
gchar * | strncasestr (const guchar *str1, const guchar *str2, size_t len) |
gchar * | strcasestr (const gchar *str1, const gchar *str2) |
gchar * | ultostr (gulong val, gint base) |
gboolean | qof_util_string_isnum (const guchar *s) |
gint | qof_util_double_compare (gdouble v1, gdouble v2) |
Compare two gdouble values. | |
const gchar * | qof_util_whitespace_filter (const gchar *val) |
gint | qof_util_bool_to_int (const gchar *val) |
gchar * | qof_util_param_to_string (QofEntity *ent, const QofParam *param) |
Converts a parameter to a string for storage or display. | |
gboolean | qof_util_param_set_string (QofEntity *ent, const QofParam *param, const gchar *value_string) |
Set a parameter from a value string. | |
gchar * | qof_util_make_utf8 (gchar *string) |
Convert strings received from the wrapped objects into UTF-8. | |
void | qof_util_string_cache_destroy (void) |
void | qof_util_string_cache_remove (gconstpointer key) |
gpointer | qof_util_string_cache_insert (gconstpointer key) |
gboolean | qof_util_param_edit (QofInstance *inst, const QofParam *param) |
Prepare to edit a parameter. | |
gboolean | qof_util_param_commit (QofInstance *inst, const QofParam *param) |
Commit this parameter change, with undo support. | |
typedef enum as string macros | |
#define | ENUM_BODY(name, value) name value, |
#define | AS_STRING_CASE(name, value) case name: { return #name; } |
#define | FROM_STRING_CASE(name, value) |
#define | DEFINE_ENUM(name, list) |
#define | AS_STRING_DEC(name, list) const gchar* name##asString(name n); |
#define | AS_STRING_FUNC(name, list) |
#define | FROM_STRING_DEC(name, list) |
#define | FROM_STRING_FUNC(name, list) |
enum as string with no typedef | |
Similar but used when the enum is NOT a typedef Make sure you use the DEFINE_ENUM_NON_TYPEDEF macro.You can precede the FROM_STRING_FUNC_NON_TYPEDEF and AS_STRING_FUNC_NON_TYPEDEF macros with the keyword static if appropriate.ENUM_BODY is used in both types. | |
#define | DEFINE_ENUM_NON_TYPEDEF(name, list) |
#define | FROM_STRING_DEC_NON_TYPEDEF(name, list) |
#define | FROM_STRING_CASE_NON_TYPEDEF(name, value) if (strcmp(str, #name) == 0) { *type = name; } |
#define | FROM_STRING_FUNC_NON_TYPEDEF(name, list) |
#define | AS_STRING_DEC_NON_TYPEDEF(name, list) const gchar* name##asString(enum name n); |
#define | AS_STRING_FUNC_NON_TYPEDEF(name, list) |
#define | AS_STRING_CASE_NON_TYPEDEF(name, value) case name: { return #name; } |
Convenience wrappers | |
void | qof_init (void) |
Initialise the Query Object Framework. | |
void | qof_close (void) |
Safely close down the Query Object Framework. |
#define AS_STRING_FUNC | ( | name, | |
list | |||
) |
#define AS_STRING_FUNC_NON_TYPEDEF | ( | name, | |
list | |||
) |
#define CACHE_REPLACE | ( | dst, | |
src | |||
) |
#define DEFINE_ENUM | ( | name, | |
list | |||
) |
#define DEFINE_ENUM_NON_TYPEDEF | ( | name, | |
list | |||
) |
#define FROM_STRING_CASE | ( | name, | |
value | |||
) |
#define FROM_STRING_DEC | ( | name, | |
list | |||
) |
#define FROM_STRING_DEC_NON_TYPEDEF | ( | name, | |
list | |||
) |
#define FROM_STRING_FUNC | ( | name, | |
list | |||
) |
#define FROM_STRING_FUNC_NON_TYPEDEF | ( | name, | |
list | |||
) |
gint null_strcmp | ( | const gchar * | da, |
const gchar * | db | ||
) | [inline] |
The null_strcmp compares strings a and b the same way that strcmp() does, except that either may be null. This routine assumes that a null string is equal to the empty string.
Definition at line 115 of file qofutil.c.
{ if (da && db) return strcmp (da, db); if (!da && db && 0 == db[0]) return 0; if (!db && da && 0 == da[0]) return 0; if (!da && db) return -1; if (da && !db) return +1; return 0; }
void qof_close | ( | void | ) |
Safely close down the Query Object Framework.
Use in place of separate close / shutdown functions (like guid_shutdown(), qof_query_shutdown() etc.) to protect against future changes.
Definition at line 780 of file qofutil.c.
{ qof_query_shutdown (); qof_object_shutdown (); guid_shutdown (); qof_date_close (); qof_util_string_cache_destroy (); }
void qof_init | ( | void | ) |
Initialise the Query Object Framework.
Use in place of separate init functions (like guid_init() and qof_query_init() etc.) to protect against future changes.
Definition at line 769 of file qofutil.c.
{ qof_util_get_string_cache (); guid_init (); qof_date_init (); qof_object_initialize (); qof_query_init (); qof_book_register (); }
gint qof_util_bool_to_int | ( | const gchar * | val | ) |
Return integer 1 if the string starts with 't' or 'T' or contains the word 'true' or 'TRUE'; if string is a number, return that number. (Leading whitespace is ignored).
Definition at line 252 of file qofutil.c.
{ const gchar *p = qof_util_whitespace_filter (val); if (!p) return 0; if ('t' == p[0]) return 1; if ('T' == p[0]) return 1; if ('y' == p[0]) return 1; if ('Y' == p[0]) return 1; if (strstr (p, "true")) return 1; if (strstr (p, "TRUE")) return 1; if (strstr (p, "yes")) return 1; if (strstr (p, "YES")) return 1; return atoi (val); }
gchar* qof_util_make_utf8 | ( | gchar * | string | ) |
Convert strings received from the wrapped objects into UTF-8.
A wrapper for g_locale_to_utf8 that removes the extra arguments. If the string is already valid UTF-8, it is returned unchanged.
Definition at line 333 of file qofutil.c.
{ gchar *value; if (!string) return NULL; if (g_utf8_validate (string, -1, NULL)) return string; value = g_locale_to_utf8 (string, -1, NULL, NULL, NULL); if (!value) { PWARN (" unable to convert from locale %s", string); PINFO ("trying to convert from ISO-8859-15."); value = g_convert (string, -1, "UTF-8", "ISO-8859-15", NULL, NULL, NULL); if (!value) { PERR (" conversion failed"); return string; } return value; } return value; }
gboolean qof_util_param_commit | ( | QofInstance * | inst, |
const QofParam * | param | ||
) |
Commit this parameter change, with undo support.
Calls the commit() routine of the backend to commit an edit. If an undo operation has been started, also maintains the undo record so the change can be undone.
param_name can only be NULL if the QofSQLite backend is not in use.
inst | The QofInstance. |
param | The parameter being modified. |
Definition at line 309 of file qofutil.c.
{ QofUndo *undo_data; QofBackend * be; if (!inst) return FALSE; (inst->editlevel)--; if (0 < inst->editlevel) return FALSE; be = qof_book_get_backend (inst->book); inst->param = param; if (be && qof_backend_commit_exists (be)) qof_backend_run_commit (be, inst); if (param != NULL) { undo_data = inst->book->undo_data; if (undo_data->undo_operation_open) qof_undo_commit (inst, param); } return TRUE; }
gboolean qof_util_param_edit | ( | QofInstance * | inst, |
const QofParam * | param | ||
) |
Prepare to edit a parameter.
Calls the begin() routine of the backend to prepare for an edit. If an undo operation has been started, also prepares an undo record.
param_name can only be NULL if the QofSQLite backend is not in use.
Making parameter changes using qof_util_param_edit and qof_util_param_commit makes for simpler QofUndo code because the undo handlers are called implicitly.
qof_book_start_operation (book, "edit PARAM_X"); param = qof_class_get_parameter(OBJ_TYPE, PARAM_NAME); retbool = qof_util_param_edit (inst, param); if (retbool) param->param_setfcn(ent, value); retbool = qof_util_param_commit (inst, param);
inst | The QofInstance. |
param | The parameter being modified. |
Definition at line 281 of file qofutil.c.
{ QofBackend *be; QofUndo *undo_data; if (!inst) return FALSE; (inst->editlevel)++; if (1 < inst->editlevel) return FALSE; if (0 >= inst->editlevel) inst->editlevel = 1; be = qof_book_get_backend (inst->book); if (param != NULL) { undo_data = inst->book->undo_data; inst->param = param; if (undo_data->undo_operation_open) qof_undo_modify (inst, param); } if (be && qof_backend_begin_exists (be)) qof_backend_run_begin (be, inst); else inst->dirty = TRUE; return TRUE; }
gboolean qof_util_param_set_string | ( | QofEntity * | ent, |
const QofParam * | param, | ||
const gchar * | value_string | ||
) |
Set a parameter from a value string.
Used by string-based backends to set a value from a string previously written out to storage.
The string must be the same format as produced by qof_util_param_to_string for the same parameter type.
ent | The entity in which the value is to be set. |
param | The parameter that stores the value. |
value_string | A string of exactly the same format as produced by qof_util_param_to_string for the parameter type. |
e.g. a numeric type would require a string like 50/100 and a time type would require a UTC date stamp like 1907-10-07T03:34:29Z
Definition at line 587 of file qofutil.c.
{ void (*string_setter) (QofEntity *, const gchar *); void (*time_setter) (QofEntity *, QofTime *); void (*numeric_setter) (QofEntity *, QofNumeric); void (*guid_setter) (QofEntity *, const GUID *); void (*double_setter) (QofEntity *, gdouble); void (*boolean_setter) (QofEntity *, gboolean); void (*i32_setter) (QofEntity *, gint32); void (*i64_setter) (QofEntity *, gint64); void (*char_setter) (QofEntity *, gchar); /* void (*kvp_frame_setter) (QofEntity *, KvpFrame *); void (*reference_setter) (QofEntity *, QofEntity *); void (*collection_setter) (QofEntity *, QofCollection *);*/ g_return_val_if_fail (ent, FALSE); g_return_val_if_fail (param, FALSE); g_return_val_if_fail (value_string, FALSE); if (safe_strcmp (param->param_type, QOF_TYPE_STRING) == 0) { string_setter = (void (*)(QofEntity *, const gchar *)) param->param_setfcn; if (string_setter != NULL) string_setter (ent, value_string); // registered_type = TRUE; } if (safe_strcmp (param->param_type, QOF_TYPE_TIME) == 0) { QofTime *qt; QofDate *qd; qd = qof_date_parse (value_string, QOF_DATE_FORMAT_UTC); if (!qd) return FALSE; qt = qof_date_to_qtime (qd); time_setter = (void (*)(QofEntity *, QofTime *)) param->param_setfcn; if ((time_setter != NULL) && (qof_time_is_valid (qt))) time_setter (ent, qt); qof_date_free (qd); // registered_type = TRUE; } if ((safe_strcmp (param->param_type, QOF_TYPE_NUMERIC) == 0) || (safe_strcmp (param->param_type, QOF_TYPE_DEBCRED) == 0)) { QofNumeric num; numeric_setter = (void (*)(QofEntity *, QofNumeric)) param->param_setfcn; if (!qof_numeric_from_string (value_string, &num) || (qof_numeric_check (num) != QOF_ERROR_OK)) return FALSE; if (numeric_setter != NULL) numeric_setter (ent, num); // registered_type = TRUE; } if (safe_strcmp (param->param_type, QOF_TYPE_GUID) == 0) { GUID * guid; guid = guid_malloc(); guid_new (guid); guid_setter = (void (*)(QofEntity *, const GUID *)) param->param_setfcn; if (!string_to_guid(value_string, guid)) return FALSE; if (guid_setter != NULL) guid_setter (ent, guid); // registered_type = TRUE; } if (safe_strcmp (param->param_type, QOF_TYPE_INT32) == 0) { gint32 i32; gchar *tail; errno = 0; i32_setter = (void (*)(QofEntity *, gint32)) param->param_setfcn; i32 = (gint32) strtol (value_string, &tail, 0); if ((i32_setter != NULL) && (errno == 0)) i32_setter (ent, i32); // registered_type = TRUE; } if (safe_strcmp (param->param_type, QOF_TYPE_INT64) == 0) { gint64 i64; gchar *tail; errno = 0; i64 = strtoll (value_string, &tail, 0); i64_setter = (void (*)(QofEntity *, gint64)) param->param_setfcn; if ((i64_setter != NULL) && (errno == 0)) i64_setter (ent, i64); // registered_type = TRUE; } if (safe_strcmp (param->param_type, QOF_TYPE_DOUBLE) == 0) { gdouble db; gchar *tail; errno = 0; db = strtod (value_string, &tail); double_setter = (void (*)(QofEntity *, gdouble)) param->param_setfcn; if ((double_setter != NULL) && (errno == 0)) double_setter (ent, db); // registered_type = TRUE; } if (safe_strcmp (param->param_type, QOF_TYPE_BOOLEAN) == 0) { gint val; gboolean b; boolean_setter = (void (*)(QofEntity *, gboolean)) param->param_setfcn; val = qof_util_bool_to_int(value_string); if ((val > 1) || (val < 0)) return FALSE; b = (val == 1) ? TRUE : FALSE; if (boolean_setter != NULL) boolean_setter (ent, val); // registered_type = TRUE; } if (safe_strcmp (param->param_type, QOF_TYPE_KVP) == 0) { /* unsupported */ return FALSE; /* KvpFrame * frame; KvpValue * value; kvp_frame_setter = (void (*)(QofEntity *, KvpFrame *)) param->param_setfcn; if (kvp_frame_setter != NULL) kvp_frame_setter (rule->targetEnt, cm_kvp); // registered_type = TRUE;*/ } if (safe_strcmp (param->param_type, QOF_TYPE_CHAR) == 0) { char_setter = (void (*)(QofEntity *, gchar)) param->param_setfcn; if (char_setter != NULL) char_setter (ent, value_string[0]); // registered_type = TRUE; } if (safe_strcmp (param->param_type, QOF_TYPE_COLLECT) == 0) { /* unsupported */ return FALSE; } if (safe_strcmp (param->param_type, QOF_TYPE_CHOICE) == 0) { /* unsupported*/ return FALSE; } /* if (registered_type == FALSE) { referenceEnt = cm_param->param_getfcn (rule->importEnt, cm_param); if (referenceEnt) { reference_setter = (void (*)(QofEntity *, QofEntity *)) cm_param-> param_setfcn; if (reference_setter != NULL) { reference_setter (rule->targetEnt, referenceEnt); } } }*/ return TRUE; }
Converts a parameter to a string for storage or display.
The returned string must be freed by the caller.
Use qof_util_param_set_string to set the parameter using the string. Designed for backends that store all values as strings.
Definition at line 404 of file qofutil.c.
{ gchar *param_string; gchar param_sa[GUID_ENCODING_LENGTH + 1]; gboolean known_type; QofType paramType; const GUID *param_guid; QofNumeric param_numeric, (*numeric_getter) (QofEntity *, const QofParam *); gdouble param_double, (*double_getter) (QofEntity *, const QofParam *); gboolean param_boolean, (*boolean_getter) (QofEntity *, const QofParam *); gint32 param_i32, (*int32_getter) (QofEntity *, const QofParam *); gint64 param_i64, (*int64_getter) (QofEntity *, const QofParam *); gchar param_char, (*char_getter) (QofEntity *, const QofParam *); param_string = NULL; known_type = FALSE; g_return_val_if_fail (ent && param, NULL); paramType = param->param_type; if (safe_strcmp (paramType, QOF_TYPE_STRING) == 0) { param_string = g_strdup (param->param_getfcn (ent, param)); if (param_string == NULL) param_string = g_strup(""); known_type = TRUE; return param_string; } if (safe_strcmp (paramType, QOF_TYPE_TIME) == 0) { QofTime *param_qt; QofDate *qd; param_qt = param->param_getfcn (ent, param); qd = qof_date_from_qtime (param_qt); return qof_date_print (qd, QOF_DATE_FORMAT_UTC); } if ((safe_strcmp (paramType, QOF_TYPE_NUMERIC) == 0) || (safe_strcmp (paramType, QOF_TYPE_DEBCRED) == 0)) { numeric_getter = (QofNumeric (*)(QofEntity *, const QofParam *)) param->param_getfcn; param_numeric = numeric_getter (ent, param); param_string = g_strdup (qof_numeric_to_string (param_numeric)); known_type = TRUE; return param_string; } if (safe_strcmp (paramType, QOF_TYPE_GUID) == 0) { param_guid = param->param_getfcn (ent, param); guid_to_string_buff (param_guid, param_sa); param_string = g_strdup (param_sa); known_type = TRUE; return param_string; } if (safe_strcmp (paramType, QOF_TYPE_INT32) == 0) { int32_getter = (gint32 (*)(QofEntity *, const QofParam *)) param->param_getfcn; param_i32 = int32_getter (ent, param); param_string = g_strdup_printf ("%d", param_i32); known_type = TRUE; return param_string; } if (safe_strcmp (paramType, QOF_TYPE_INT64) == 0) { int64_getter = (gint64 (*)(QofEntity *, const QofParam *)) param->param_getfcn; param_i64 = int64_getter (ent, param); param_string = g_strdup_printf ("%" G_GINT64_FORMAT, param_i64); known_type = TRUE; return param_string; } if (safe_strcmp (paramType, QOF_TYPE_DOUBLE) == 0) { double_getter = (double (*)(QofEntity *, const QofParam *)) param->param_getfcn; param_double = double_getter (ent, param); param_string = g_strdup_printf ("%f", param_double); known_type = TRUE; return param_string; } if (safe_strcmp (paramType, QOF_TYPE_BOOLEAN) == 0) { boolean_getter = (gboolean (*)(QofEntity *, const QofParam *)) param->param_getfcn; param_boolean = boolean_getter (ent, param); /* Boolean values need to be lowercase for QSF validation. */ if (param_boolean == TRUE) { param_string = g_strdup ("true"); } else { param_string = g_strdup ("false"); } known_type = TRUE; return param_string; } /* "kvp" contains repeating values, cannot be a single string for the frame. */ if (safe_strcmp (paramType, QOF_TYPE_KVP) == 0) { KvpFrame *frame = NULL; frame = param->param_getfcn (ent, param); known_type = TRUE; if (!kvp_frame_is_empty (frame)) { GHashTable *hash = kvp_frame_get_hash (frame); param_string = g_strdup_printf ("%s(%d)", QOF_TYPE_KVP, g_hash_table_size (hash)); } /* ensure a newly allocated string is returned, even if the frame is empty. */ else { param_string = g_strdup(""); } return param_string; } if (safe_strcmp (paramType, QOF_TYPE_CHAR) == 0) { char_getter = (gchar (*)(QofEntity *, const QofParam *)) param->param_getfcn; param_char = char_getter (ent, param); known_type = TRUE; return g_strdup_printf ("%c", param_char); } /* "collect" contains repeating values, cannot be a single string. */ if (safe_strcmp (paramType, QOF_TYPE_COLLECT) == 0) { QofCollection *col = NULL; col = param->param_getfcn (ent, param); known_type = TRUE; return g_strdup_printf ("%s(%d)", qof_collection_get_type (col), qof_collection_count (col)); } if (safe_strcmp (paramType, QOF_TYPE_CHOICE) == 0) { QofEntity *child = NULL; child = param->param_getfcn (ent, param); if (!child) { return param_string; } known_type = TRUE; return g_strdup (qof_object_printable (child->e_type, child)); } if (safe_strcmp (paramType, QOF_PARAM_BOOK) == 0) { QofBackend *be; QofBook *book; book = param->param_getfcn (ent, param); PINFO (" book param %p", book); be = qof_book_get_backend (book); known_type = TRUE; PINFO (" backend=%p", be); if (!be) { return QOF_PARAM_BOOK; } param_string = g_strdup (be->fullpath); PINFO (" fullpath=%s", param_string); if (param_string) { return param_string; } param_guid = qof_entity_get_guid ((QofEntity*)book); guid_to_string_buff (param_guid, param_sa); PINFO (" book GUID=%s", param_sa); param_string = g_strdup (param_sa); return param_string; } if (!known_type) { QofEntity *child = NULL; child = param->param_getfcn (ent, param); if (!child) { return param_string; } return g_strdup (qof_object_printable (child->e_type, child)); } return g_strdup (""); }
void qof_util_string_cache_destroy | ( | void | ) |
The QOF String Cache:
Many strings used throughout QOF and QOF applications are likely to be duplicated.
QOF provides a reference counted cache system for the strings, which shares strings whenever possible.
Use qof_util_string_cache_insert to insert a string into the cache (it will return a pointer to the cached string). Basically you should use this instead of g_strdup.
Use qof_util_string_cache_remove (giving it a pointer to a cached string) if the string is unused. If this is the last reference to the string it will be removed from the cache, otherwise it will just decrement the reference count. Basically you should use this instead of g_free.
Just in case it's not clear: The remove function must NOT be called for the string you passed INTO the insert function. It must be called for the _cached_ string that is _returned_ by the insert function.
Note that all the work is done when inserting or removing. Once cached the strings are just plain C strings.
The string cache is demand-created on first use. Destroy the qof_util_string_cache
Definition at line 381 of file qofutil.c.
{
if (qof_string_cache)
g_cache_destroy (qof_string_cache);
qof_string_cache = NULL;
}
gpointer qof_util_string_cache_insert | ( | gconstpointer | key | ) |
void qof_util_string_cache_remove | ( | gconstpointer | key | ) |
gboolean qof_util_string_isnum | ( | const guchar * | s | ) |
Returns true if string s is a number, possibly surrounded by whitespace.
Definition at line 198 of file qofutil.c.
{ if (s == NULL) return FALSE; if (*s == 0) return FALSE; while (*s && isspace (*s)) s++; if (*s == 0) return FALSE; if (!isdigit (*s)) return FALSE; while (*s && isdigit (*s)) s++; if (*s == 0) return TRUE; while (*s && isspace (*s)) s++; if (*s == 0) return TRUE; return FALSE; }
const gchar* qof_util_whitespace_filter | ( | const gchar * | val | ) |
gint safe_strcasecmp | ( | const gchar * | da, |
const gchar * | db | ||
) |
case sensitive comparison of strings da and db - either may be NULL. A non-NULL string is greater than a NULL string.
da | string 1. |
db | string 2. |
Definition at line 95 of file qofutil.c.
{ if ((da) && (db)) { if ((da) != (db)) { gint retval = strcasecmp ((da), (db)); /* if strings differ, return */ if (retval) return retval; } } else if ((!(da)) && (db)) return -1; else if ((da) && (!(db))) return +1; return 0; }
gint safe_strcmp | ( | const gchar * | da, |
const gchar * | db | ||
) |
The safe_strcmp compares strings da and db the same way that strcmp() does, except that either may be null. This routine assumes that a non-null string is always greater than a null string.
da | string 1. |
db | string 2. |
Definition at line 75 of file qofutil.c.
{ if ((da) && (db)) { if ((da) != (db)) { gint retval = strcmp ((da), (db)); /* if strings differ, return */ if (retval) return retval; } } else if ((!(da)) && (db)) return -1; else if ((da) && (!(db))) return +1; return 0; }
gchar* strncasestr | ( | const guchar * | str1, |
const guchar * | str2, | ||
size_t | len | ||
) |
Search for str2 in first nchar chars of str1, ignore case. Return pointer to first match, or null. These are just like that strnstr and the strstr functions, except that they ignore the case.
Definition at line 45 of file qofutil.c.
{ while (*str1 && len--) { if (toupper (*str1) == toupper (*str2)) { size_t l; l = strlen ((gchar*)str2); if (strncasecmp ((gchar*)str1, (gchar*)str2, l) == 0) return (gchar *) str1; } str1++; } return NULL; }
gchar* ultostr | ( | gulong | val, |
gint | base | ||
) |
The ultostr() subroutine is the inverse of strtoul(). It accepts a number and prints it in the indicated base. The returned string should be g_freed when done.
Definition at line 134 of file qofutil.c.
{ gchar buf[MAX_DIGITS]; gulong broke[MAX_DIGITS]; gint i; gulong places = 0, reval; if ((2 > base) || (36 < base)) return NULL; /* count digits */ places = 0; for (i = 0; i < MAX_DIGITS; i++) { broke[i] = val; places++; val /= base; if (0 == val) break; } /* normalize */ reval = 0; for (i = places - 2; i >= 0; i--) { reval += broke[i + 1]; reval *= base; broke[i] -= reval; } /* print */ for (i = 0; i < (gint) places; i++) { if (10 > broke[i]) { buf[places - 1 - i] = 0x30 + broke[i]; /* ascii digit zero */ } else { buf[places - 1 - i] = 0x41 - 10 + broke[i]; /* ascii capital A */ } } buf[places] = 0x0; return g_strdup (buf); }