From b5781e4174975388a7c3f077723bff66b974b538 Mon Sep 17 00:00:00 2001 From: Ken Raeburn Date: Wed, 27 Oct 2004 00:07:20 +0000 Subject: [PATCH] Permit exporting profile file data into a buffer * prof_file.c (profile_flush_file_data_to_buffer): New function. * profi_init.c (profile_flush_to_buffer, profile_free_buffer): New functions. * prof_parse.c (output_quoted_string): Use a callback instead of stdio calls. (dump_profile): Renamed from dump_profile_to_file. Use a callback instead of stdio calls. (dump_profile_to_file_cb): New function. (profile_write_tree_file): Updated to new internal interface. (struct prof_buf): New type. (add_data_to_buffer, dump_profile_to_buffer_cb, profile_write_tree_to_buffer): New functions. * prof_int.h (profile_write_tree_to_buffer, profile_flush_file_data_to_buffer): Declare. * profile.hin (profile_flush_to_buffer, profile_free_buffer): Declare. * libprofile.exports: Export profile_flush_to_buffer and profile_free_buffer. * profile.swg (profile_flush_to_buffer): Declare. * profile_tcl.c: Regenerated. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@16838 dc483132-0cff-0310-8789-dd5450dbe970 --- src/util/profile/ChangeLog | 24 +++++ src/util/profile/libprofile.exports | 2 + src/util/profile/prof_file.c | 11 +++ src/util/profile/prof_init.c | 12 +++ src/util/profile/prof_int.h | 6 ++ src/util/profile/prof_parse.c | 137 +++++++++++++++++++++------- src/util/profile/profile.hin | 4 + src/util/profile/profile.swg | 2 + src/util/profile/profile_tcl.c | 49 ++++++++++ 9 files changed, 215 insertions(+), 32 deletions(-) diff --git a/src/util/profile/ChangeLog b/src/util/profile/ChangeLog index f48a24c33..1366bd4d1 100644 --- a/src/util/profile/ChangeLog +++ b/src/util/profile/ChangeLog @@ -1,3 +1,27 @@ +2004-10-26 Ken Raeburn + + Permit exporting profile file data into a buffer. + * prof_file.c (profile_flush_file_data_to_buffer): New function. + * profi_init.c (profile_flush_to_buffer, profile_free_buffer): New + functions. + * prof_parse.c (output_quoted_string): Use a callback instead of + stdio calls. + (dump_profile): Renamed from dump_profile_to_file. Use a callback + instead of stdio calls. + (dump_profile_to_file_cb): New function. + (profile_write_tree_file): Updated to new internal interface. + (struct prof_buf): New type. + (add_data_to_buffer, dump_profile_to_buffer_cb, + profile_write_tree_to_buffer): New functions. + * prof_int.h (profile_write_tree_to_buffer, + profile_flush_file_data_to_buffer): Declare. + * profile.hin (profile_flush_to_buffer, profile_free_buffer): + Declare. + * libprofile.exports: Export profile_flush_to_buffer and + profile_free_buffer. + * profile.swg (profile_flush_to_buffer): Declare. + * profile_tcl.c: Regenerated. + 2004-10-22 Ken Raeburn * prof_file.c (profile_update_file_data): When resetting flags, diff --git a/src/util/profile/libprofile.exports b/src/util/profile/libprofile.exports index 2df95fe25..26db5e898 100644 --- a/src/util/profile/libprofile.exports +++ b/src/util/profile/libprofile.exports @@ -51,3 +51,5 @@ profile_update_relation profile_verify_node profile_write_tree_file profile_flush_to_file +profile_flush_to_buffer +profile_free_buffer diff --git a/src/util/profile/prof_file.c b/src/util/profile/prof_file.c index 17f943a66..f47e5404b 100644 --- a/src/util/profile/prof_file.c +++ b/src/util/profile/prof_file.c @@ -452,6 +452,17 @@ errout: return retval; } +errcode_t profile_flush_file_data_to_buffer (prf_data_t data, char **bufp) +{ + errcode_t retval; + retval = k5_mutex_lock(&data->lock); + if (retval) + return retval; + retval = profile_write_tree_to_buffer(data->root, bufp); + k5_mutex_unlock(&data->lock); + return retval; +} + errcode_t profile_flush_file_data(prf_data_t data) { errcode_t retval = 0; diff --git a/src/util/profile/prof_init.c b/src/util/profile/prof_init.c index 6b04d61e5..02d61ee1f 100644 --- a/src/util/profile/prof_init.c +++ b/src/util/profile/prof_init.c @@ -145,6 +145,18 @@ profile_flush_to_file(profile_t profile, const_profile_filespec_t outfile) return 0; } +errcode_t KRB5_CALLCONV +profile_flush_to_buffer(profile_t profile, char **buf) +{ + return profile_flush_file_data_to_buffer(profile->first_file->data, buf); +} + +void KRB5_CALLCONV +profile_free_buffer(profile_t profile, char *buf) +{ + free(buf); +} + void KRB5_CALLCONV profile_abandon(profile_t profile) { diff --git a/src/util/profile/prof_int.h b/src/util/profile/prof_int.h index 60cadbdf0..d2761228c 100644 --- a/src/util/profile/prof_int.h +++ b/src/util/profile/prof_int.h @@ -99,6 +99,9 @@ errcode_t profile_parse_file errcode_t profile_write_tree_file (struct profile_node *root, FILE *dstfile); +errcode_t profile_write_tree_to_buffer + (struct profile_node *root, char **buf); + /* prof_tree.c */ @@ -193,6 +196,9 @@ errcode_t profile_flush_file_data errcode_t profile_flush_file_data_to_file (prf_data_t data, const char *outfile); +errcode_t profile_flush_file_data_to_buffer + (prf_data_t data, char **bufp); + void profile_free_file (prf_file_t profile); diff --git a/src/util/profile/prof_parse.c b/src/util/profile/prof_parse.c index 042379dd2..d229bbb3a 100644 --- a/src/util/profile/prof_parse.c +++ b/src/util/profile/prof_parse.c @@ -319,35 +319,42 @@ static int need_double_quotes(char *str) * Output a string with double quotes, doing appropriate backquoting * of characters as necessary. */ -static void output_quoted_string(char *str, FILE *f) +static void output_quoted_string(char *str, void (*cb)(const char *,void *), + void *data) { char ch; - - fputc('"', f); + char buf[2]; + + cb("\"", data); if (!str) { - fputc('"', f); + cb("\"", data); return; } + buf[1] = 0; while ((ch = *str++)) { switch (ch) { case '\\': - fputs("\\\\", f); + cb("\\\\", data); break; case '\n': - fputs("\\n", f); + cb("\\n", data); break; case '\t': - fputs("\\t", f); + cb("\\t", data); break; case '\b': - fputs("\\b", f); + cb("\\b", data); break; default: - fputc(ch, f); + /* This would be a lot faster if we scanned + forward for the next "interesting" + character. */ + buf[0] = ch; + cb(buf, data); break; } } - fputc('"', f); + cb("\"", data); } @@ -360,8 +367,9 @@ static void output_quoted_string(char *str, FILE *f) #define EOL "\n" #endif -static void dump_profile_to_file(struct profile_node *root, int level, - FILE *dstfile) +/* Errors should be returned, not ignored! */ +static void dump_profile(struct profile_node *root, int level, + void (*cb)(const char *, void *), void *data) { int i; struct profile_node *p; @@ -376,14 +384,18 @@ static void dump_profile_to_file(struct profile_node *root, int level, if (retval) break; for (i=0; i < level; i++) - fprintf(dstfile, "\t"); + cb("\t", data); if (need_double_quotes(value)) { - fputs(name, dstfile); - fputs(" = ", dstfile); - output_quoted_string(value, dstfile); - fputs(EOL, dstfile); - } else - fprintf(dstfile, "%s = %s%s", name, value, EOL); + cb(name, data); + cb(" = ", data); + output_quoted_string(value, cb, data); + cb(EOL, data); + } else { + cb(name, data); + cb(" = ", data); + cb(value, data); + cb(EOL, data); + } } while (iter != 0); iter = 0; @@ -393,27 +405,88 @@ static void dump_profile_to_file(struct profile_node *root, int level, if (retval) break; if (level == 0) { /* [xxx] */ - for (i=0; i < level; i++) - fprintf(dstfile, "\t"); - fprintf(dstfile, "[%s]%s%s", name, - profile_is_node_final(p) ? "*" : "", EOL); - dump_profile_to_file(p, level+1, dstfile); - fprintf(dstfile, EOL); + cb("[", data); + cb(name, data); + cb("]", data); + cb(profile_is_node_final(p) ? "*" : "", data); + cb(EOL, data); + dump_profile(p, level+1, cb, data); + cb(EOL, data); } else { /* xxx = { ... } */ for (i=0; i < level; i++) - fprintf(dstfile, "\t"); - fprintf(dstfile, "%s = {%s", name, EOL); - dump_profile_to_file(p, level+1, dstfile); + cb("\t", data); + cb(name, data); + cb(" = {", data); + cb(EOL, data); + dump_profile(p, level+1, cb, data); for (i=0; i < level; i++) - fprintf(dstfile, "\t"); - fprintf(dstfile, "}%s%s", - profile_is_node_final(p) ? "*" : "", EOL); + cb("\t", data); + cb("}", data); + cb(profile_is_node_final(p) ? "*" : "", data); + cb(EOL, data); } } while (iter != 0); } +static void dump_profile_to_file_cb(const char *str, void *data) +{ + fputs(str, data); +} + errcode_t profile_write_tree_file(struct profile_node *root, FILE *dstfile) { - dump_profile_to_file(root, 0, dstfile); + dump_profile(root, 0, dump_profile_to_file_cb, dstfile); + return 0; +} + +struct prof_buf { + char *base; + size_t cur, max; + int err; +}; + +static void add_data_to_buffer(struct prof_buf *b, const void *d, size_t len) +{ + if (b->err) + return; + if (b->max - b->cur < len) { + size_t newsize; + char *newptr; + + newsize = b->max + (b->max >> 1) + len + 1024; + newptr = realloc(b->base, newsize); + if (newptr == NULL) { + b->err = 1; + return; + } + b->base = newptr; + b->max = newsize; + } + memcpy(b->base + b->cur, d, len); + b->cur += len; /* ignore overflow */ +} + +static void dump_profile_to_buffer_cb(const char *str, void *data) +{ + add_data_to_buffer((struct prof_buf *)data, str, strlen(str)); +} + +errcode_t profile_write_tree_to_buffer(struct profile_node *root, + char **buf) +{ + struct prof_buf prof_buf = { 0, 0, 0, 0 }; + + dump_profile(root, 0, dump_profile_to_buffer_cb, &prof_buf); + if (prof_buf.err) { + *buf = NULL; + return ENOMEM; + } + add_data_to_buffer(&prof_buf, "", 1); /* append nul */ + if (prof_buf.max - prof_buf.cur > (prof_buf.max >> 3)) { + char *newptr = realloc(prof_buf.base, prof_buf.cur); + if (newptr) + prof_buf.base = newptr; + } + *buf = prof_buf.base; return 0; } diff --git a/src/util/profile/profile.hin b/src/util/profile/profile.hin index d5a1b5e9e..ec822ca8b 100644 --- a/src/util/profile/profile.hin +++ b/src/util/profile/profile.hin @@ -49,6 +49,10 @@ long KRB5_CALLCONV profile_flush (profile_t profile); long KRB5_CALLCONV profile_flush_to_file (profile_t profile, const_profile_filespec_t outfile); +long KRB5_CALLCONV profile_flush_to_buffer + (profile_t profile, char **bufp); +void KRB5_CALLCONV profile_free_buffer + (profile_t profile, char *buf); void KRB5_CALLCONV profile_abandon (profile_t profile); diff --git a/src/util/profile/profile.swg b/src/util/profile/profile.swg index d6f16b7fe..7398e14a0 100644 --- a/src/util/profile/profile.swg +++ b/src/util/profile/profile.swg @@ -250,6 +250,8 @@ errcode_t profile_rename_section(profile_t p, const char **nullterm, const char *new_name = NULL); errcode_t profile_add_relation(profile_t p, const char **nullterm, const char *new_val = NULL); +/* XXX Should be using profile_free_buffer blah. */ +errcode_t profile_flush_to_buffer(profile_t p, char **OUTPUT); #ifdef SWIGTCL %include "tclsh.i" diff --git a/src/util/profile/profile_tcl.c b/src/util/profile/profile_tcl.c index a4c37906c..9b75e74b4 100644 --- a/src/util/profile/profile_tcl.c +++ b/src/util/profile/profile_tcl.c @@ -2011,6 +2011,54 @@ _wrap_profile_add_relation(ClientData clientData, Tcl_Interp *interp, int objc, } +static int +_wrap_profile_flush_to_buffer(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + profile_t arg1 = (profile_t) 0 ; + char **arg2 = (char **) 0 ; + errcode_t result; + char *tmp2 ; + + { + /* in char **OUTPUT */ + tmp2 = NULL; + arg2 = &tmp2; + } + if (SWIG_GetArgs(interp, objc, objv,"o:profile_flush_to_buffer p ",0) == TCL_ERROR) SWIG_fail; + if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail; + result = (errcode_t)profile_flush_to_buffer(arg1,arg2); + + { + /* out errcode_t result */ + if (result) { + /* There could be a memory leak here in the SWIG-Tcl layer, + I'm not sure. Not going to worry about it though. */ + Tcl_SetResult(interp, error_message(result), TCL_STATIC); + SWIG_fail; + } + } + { + /* argout char **OUTPUT */ + /* Tcl_SetResult(interp, *arg2, TCL_DYNAMIC); */ + char *s = (arg2 && *arg2) ? *arg2 : ""; + Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp), + Tcl_NewStringObj(s, strlen(s))); + } + { + /* There may be a memory leak here. Investigate later, if anyone + cares. */ + /* profile_release_string(*arg2); */ + } + return TCL_OK; + fail: + { + /* There may be a memory leak here. Investigate later, if anyone + cares. */ + /* profile_release_string(*arg2); */ + } + return TCL_ERROR; +} + + static swig_command_info swig_commands[] = { { SWIG_prefix "profile_init_path", (swig_wrapper_func) _wrap_profile_init_path, NULL}, @@ -2032,6 +2080,7 @@ static swig_command_info swig_commands[] = { { SWIG_prefix "profile_clear_relation", (swig_wrapper_func) _wrap_profile_clear_relation, NULL}, { SWIG_prefix "profile_rename_section", (swig_wrapper_func) _wrap_profile_rename_section, NULL}, { SWIG_prefix "profile_add_relation", (swig_wrapper_func) _wrap_profile_add_relation, NULL}, + { SWIG_prefix "profile_flush_to_buffer", (swig_wrapper_func) _wrap_profile_flush_to_buffer, NULL}, {0, 0, 0} }; -- 2.26.2