From 3c2db26c6dbb4d19d137e07e6aec6306724cbb82 Mon Sep 17 00:00:00 2001 From: Theodore Tso Date: Thu, 20 Apr 1995 14:57:45 +0000 Subject: [PATCH] Initial checkin of the profile library git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@5382 dc483132-0cff-0310-8789-dd5450dbe970 --- src/util/profile/.cvsignore | 1 + src/util/profile/Makefile.in | 52 ++++ src/util/profile/configure.in | 9 + src/util/profile/dosshell.ini | 537 ++++++++++++++++++++++++++++++++ src/util/profile/krb5.conf | 12 + src/util/profile/prof_err.et | 41 +++ src/util/profile/prof_file.c | 76 +++++ src/util/profile/prof_init.c | 157 ++++++++++ src/util/profile/prof_int.h | 119 +++++++ src/util/profile/prof_parse.c | 220 +++++++++++++ src/util/profile/prof_section.c | 168 ++++++++++ src/util/profile/prof_tree.c | 334 ++++++++++++++++++++ src/util/profile/profile.h.in | 20 ++ src/util/profile/test.ini | 46 +++ src/util/profile/test_parse.c | 43 +++ src/util/profile/test_profile.c | 45 +++ 16 files changed, 1880 insertions(+) create mode 100644 src/util/profile/.cvsignore create mode 100644 src/util/profile/Makefile.in create mode 100644 src/util/profile/configure.in create mode 100644 src/util/profile/dosshell.ini create mode 100644 src/util/profile/krb5.conf create mode 100644 src/util/profile/prof_err.et create mode 100644 src/util/profile/prof_file.c create mode 100644 src/util/profile/prof_init.c create mode 100644 src/util/profile/prof_int.h create mode 100644 src/util/profile/prof_parse.c create mode 100644 src/util/profile/prof_section.c create mode 100644 src/util/profile/prof_tree.c create mode 100644 src/util/profile/profile.h.in create mode 100644 src/util/profile/test.ini create mode 100644 src/util/profile/test_parse.c create mode 100644 src/util/profile/test_profile.c diff --git a/src/util/profile/.cvsignore b/src/util/profile/.cvsignore new file mode 100644 index 000000000..e8c05a6b1 --- /dev/null +++ b/src/util/profile/.cvsignore @@ -0,0 +1 @@ +configure diff --git a/src/util/profile/Makefile.in b/src/util/profile/Makefile.in new file mode 100644 index 000000000..0537db82d --- /dev/null +++ b/src/util/profile/Makefile.in @@ -0,0 +1,52 @@ +CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE) + +LOCALINCLUDE=-I. -I$(srcdir)/../et + +OBJS = prof_tree.o \ + prof_file.o \ + prof_parse.o \ + prof_err.o \ + prof_init.o + +SRCS = $(srcdir)/prof_tree.c \ + $(srcdir)/prof_file.c \ + $(srcdir)/prof_parse.c \ + prof_err.c \ + $(srcdir)/prof_init.c + +LIBS = ../et/libcom_err.a + +all:: includes libprofile.a test_parse + +libprofile.a: $(OBJS) + $(ARCHIVE) $@ $(OBJS) + $(RANLIB) $@ + +test_parse: test_parse.o $(OBJS) $(LIBS) + cc -o test_parse test_parse.o $(OBJS) $(LIBS) + +test_profile: test_profile.o $(OBJS) $(LIBS) + cc -o test_profile test_profile.o $(OBJS) $(LIBS) + +profile.h: prof_err.h profile.h.in + cat $(srcdir)/profile.h.in prof_err.h > $@ + +prof_err.h: prof_err.et + +prof_err.c: prof_err.et + +clean:: + rm -f $(PROGS) *.o *~ test_parse core libprofile.a prof_err.h \ + prof_err.c + +# +++ Dependency line eater +++ +# +# Makefile dependencies follow. This must be the last section in +# the Makefile.in file +# +prof_tree.o : $(srcdir)/prof_tree.c $(srcdir)/prof_int.h ./prof_err.h +prof_file.o : $(srcdir)/prof_file.c $(srcdir)/prof_int.h ./prof_err.h +prof_parse.o : $(srcdir)/prof_parse.c $(srcdir)/prof_int.h ./prof_err.h +prof_err.o : prof_err.c +prof_init.o : $(srcdir)/prof_init.c $(srcdir)/prof_int.h ./prof_err.h + diff --git a/src/util/profile/configure.in b/src/util/profile/configure.in new file mode 100644 index 000000000..364e45edf --- /dev/null +++ b/src/util/profile/configure.in @@ -0,0 +1,9 @@ +AC_INIT(prof_parse.c) +WITH_CCOPTS +CONFIG_RULES +AC_SET_BUILDTOP +AC_PROG_ARCHIVE +AC_PROG_RANLIB +ET_RULES +CopyHeader(profile.h,$(BUILDTOP)/include) +V5_AC_OUTPUT_MAKEFILE diff --git a/src/util/profile/dosshell.ini b/src/util/profile/dosshell.ini new file mode 100644 index 000000000..cec96ec59 --- /dev/null +++ b/src/util/profile/dosshell.ini @@ -0,0 +1,537 @@ +EGA.INI/VGA.INI +**************** WARNING ******************** +This file may contain lines with more than 256 +characters. Some editors will truncate or split +these lines. If you are not sure whether your +editor can handle long lines, exit now without +saving the file. + +Note: The editor which is invoked by the + MS-DOS 5.0 EDIT command can be used + to edit this file. +**************** NOTE *********************** +Everything up to the first left square bracket +character is considered a comment. +*********************************************** +[savestate] +screenmode = text +resolution = low +startup = filemanager +filemanagermode = shared +sortkey = name +pause = disabled +explicitselection = disabled +swapmouse = disabled +tasklist = disabled +switching = disabled +[programstarter] +currentcolor = Ocean +filemanager = enabled +command = enabled +group = +{ + program = + { + command = COMMAND + title = Command Prompt + help = Starts the MS-DOS command prompt where you can type any MS-DOS command.^m^mTo return to MS-DOS Shell from the command line:^m^m1. Type exit^m2. Press ENTER.^m^mRelated Topic^m " More on Command Prompt "~$129~ + pause = disabled + } + program = + { + command = EDIT %1 + title = Editor + help = Starts MS-DOS Editor, a text editor you can use to create and modify text files. After you choose Editor, you can specify the file you want to work with in a dialog box.^m^mRelated Topic^m " More on Editor "~$130~ + pause = disabled + dialog = + { + title = File to Edit + info = Enter the name of the file to edit. To start MS-DOS Editor without opening a file, press ENTER. + prompt = File to edit? + parameter = %1 + } + } + program = + { + command = QBASIC %1 + title = MS-DOS QBasic + help = Starts MS-DOS QBasic, a programming environment you can use to create, modify, run, and debug programs. After you choose MS-DOS QBasic, you can specify the file you want to work with in a dialog box.^m^mRelated Topic^m " More on MS-DOS QBasic "~$131~ + pause = disabled + dialog = + { + title = MS-DOS QBasic File + info = Enter the name of a QBasic program. To start without opening a program, press ENTER. + prompt = QBasic File? + parameter = %1 + } + } + group = + { + title = Disk Utilities + help = Displays program items you can choose to manage your disks. You can also choose to open the Main group or any group you may have added. + program = + { + command = diskcopy %1 + title = Disk Copy + pause = enabled + dialog = + { + title = Disk Copy + info = Enter the source and destination drives. + prompt = Parameters . . . + default = a: b: + parameter = %1 + } + help = Temporarily leaves MS-DOS Shell to copy the contents of a floppy disk to another floppy disk. After you choose Disk Copy, a dialog box suggests parameters and switches you can either accept or replace.^m^mRelated Topic^m " More on Disk Copy "~$132~ + } + program = + { + command = backup %1 + title = Backup Fixed Disk + pause = enabled + dialog = + { + title = Backup Fixed Disk + info = Enter the source and destination drives. + prompt = Parameters . . . + default = c:\*.* a: /s + parameter = %1 + } + help = Temporarily leaves MS-DOS Shell to copy files from one disk to another. After you choose Backup Fixed Disk, a dialog box suggests parameters and switches you can either accept or replace.^m^mRelated Topic^m " More on Backup Fixed Disk "~$133~ + } + program = + { + command = restore %1 + title = Restore Fixed Disk + pause = enabled + dialog = + { + title = Restore Fixed Disk + info = Enter the source and destination drives. + prompt = Parameters . . . + parameter = %1 + } + help = Temporarily leaves MS-DOS Shell to restore files that were backed up. After you choose Restore Fixed Disk, a dialog box suggests parameters and switches you can either accept or replace.^m^mRelated Topic^m " More on Restore Fixed Disk "~$134~ + } + program = + { + command = format %1 /q + title = Quick Format + pause = enabled + dialog = + { + title = Quick Format + info = Enter the drive to quick format. + prompt = Parameters . . . + default = a: + parameter = %1 + } + help = Temporarily leaves MS-DOS Shell to prepare a disk to accept MS-DOS files. After you choose Quick Format, a dialog box suggests parameters and switches you can either accept or replace.^m^mRelated Topic^m " More on Quick Format "~$136~ + screenmode = text + alttab = enabled + altesc = enabled + ctrlesc = enabled + prevent = enabled + } + program = + { + command = format %1 + title = Format + pause = enabled + dialog = + { + title = Format + info = Enter the drive to format. + prompt = Parameters . . . + default = a: + parameter = %1 + } + help = Temporarily leaves MS-DOS Shell to prepare a disk to accept MS-DOS files. After you choose Format, a dialog box suggests parameters and switches you can either accept or replace.^m^mRelated Topic^m " More on Format "~$135~ + } + program = + { + command = undelete %1 + title = Undelete + help = Recovers deleted files.^m^mWARNING: If your disk is full or if you are using task swapping, using this program item may render some deleted files unrecoverable.^m^mRelated Procedure^m " Restoring Deleted Files "~I155~ + pause = enabled + dialog = + { + title = Undelete + info = WARNING! This action may cause the permanent loss of some deleted files. Press F1 for more information. + prompt = Parameters . . . + default = /LIST + parameter = %1 + } + screenmode = text + alttab = enabled + altesc = enabled + ctrlesc = enabled + prevent = enabled + } + } +} +color = +{ + selection = + { + title = Basic Blue + foreground = + { + base = black + highlight = brightwhite + selection = brightwhite + alert = brightred + menubar = black + menu = black + disabled = white + accelerator = cyan + dialog = black + button = black + elevator = white + titlebar = black + scrollbar = brightwhite + borders = black + drivebox = black + driveicon = black + cursor = black + } + background = + { + base = brightwhite + highlight = blue + selection = black + alert = brightwhite + menubar = white + menu = brightwhite + disabled = brightwhite + accelerator = brightwhite + dialog = brightwhite + button = white + elevator = white + titlebar = white + scrollbar = black + borders = brightwhite + drivebox = brightwhite + driveicon = brightwhite + cursor = brightblack + } + } + selection = + { + title = Ocean + foreground = + { + base = black + highlight = brightwhite + selection = brightwhite + alert = brightwhite + menubar = black + menu = black + disabled = white + accelerator = brightwhite + dialog = black + button = black + elevator = white + titlebar = black + scrollbar = brightwhite + borders = black + drivebox = black + driveicon = black + cursor = black + } + background = + { + base = brightwhite + highlight = blue + selection = black + alert = white + menubar = cyan + menu = cyan + disabled = cyan + accelerator = cyan + dialog = cyan + button = brightwhite + elevator = white + titlebar = white + scrollbar = black + borders = black + drivebox = brightwhite + driveicon = brightwhite + cursor = brightcyan + } + } + selection = + { + title = Monochrome-2 Colors + foreground = + { + base = black + highlight = white + selection = white + alert = black + menubar = black + menu = black + disabled = white + accelerator = white + dialog = black + button = white + elevator = black + titlebar = white + scrollbar = white + borders = black + drivebox = black + driveicon = black + } + background = + { + base = white + highlight = black + selection = black + alert = white + menubar = white + menu = white + disabled = white + accelerator = black + dialog = white + button = black + elevator = white + titlebar = black + scrollbar = black + borders = black + drivebox = white + driveicon = white + } + } + selection = + { + title = Monochrome-4 Colors + foreground = + { + base = black + highlight = brightwhite + selection = brightwhite + alert = black + menubar = black + menu = black + disabled = white + accelerator = brightwhite + dialog = black + button = black + elevator = white + titlebar = black + scrollbar = brightwhite + borders = black + drivebox = black + driveicon = black + cursor = black + } + background = + { + base = brightwhite + highlight = brightblack + selection = brightblack + alert = brightwhite + menubar = brightwhite + menu = white + disabled = white + accelerator = brightblack + dialog = brightwhite + button = white + elevator = white + titlebar = white + scrollbar = black + borders = black + drivebox = brightwhite + driveicon = brightwhite + cursor = black + } + } + selection = + { + title = Reverse + foreground = + { + base = white + highlight = black + selection = black + alert = white + menubar = white + menu = white + disabled = black + accelerator = black + dialog = white + button = black + elevator = white + titlebar = black + scrollbar = black + borders = white + drivebox = white + driveicon = white + } + background = + { + base = black + highlight = white + selection = white + alert = black + menubar = black + menu = black + disabled = black + accelerator = white + dialog = black + button = white + elevator = black + titlebar = white + scrollbar = white + borders = black + drivebox = black + driveicon = black + } + } + selection = + { + title = Hot Pink + foreground = + { + base = black + highlight = brightwhite + selection = brightwhite + alert = brightmagenta + menubar = black + menu = black + disabled = white + accelerator = magenta + dialog = black + button = brightwhite + elevator = white + titlebar = brightwhite + scrollbar = brightwhite + borders = black + drivebox = black + driveicon = black + cursor = black + } + background = + { + base = brightwhite + highlight = brightmagenta + selection = magenta + alert = brightwhite + menubar = brightwhite + menu = brightwhite + disabled = brightwhite + accelerator = brightwhite + dialog = brightwhite + button = magenta + elevator = white + titlebar = magenta + scrollbar = black + borders = black + drivebox = brightwhite + driveicon = brightwhite + cursor = brightred + } + } + selection = + { + title = Emerald City + foreground = + { + base = black + highlight = black + selection = brightwhite + alert = green + menubar = black + menu = black + disabled = white + accelerator = green + dialog = black + button = brightwhite + elevator = white + titlebar = brightwhite + scrollbar = brightwhite + borders = black + drivebox = black + driveicon = black + cursor = black + } + background = + { + base = brightwhite + highlight = brightgreen + selection = green + alert = brightwhite + menubar = brightwhite + menu = brightwhite + disabled = brightwhite + accelerator = brightwhite + dialog = brightwhite + button = green + elevator = white + titlebar = green + scrollbar = black + borders = black + drivebox = brightwhite + driveicon = brightwhite + cursor = brightcyan + } + } + selection = + { + title = Turquoise + foreground = + { + base = black + highlight = brightwhite + selection = brightwhite + alert = brightred + menubar = brightwhite + menu = black + disabled = white + accelerator = white + dialog = black + button = black + elevator = white + titlebar = black + scrollbar = brightwhite + borders = black + drivebox = black + driveicon = black + cursor = black + } + background = + { + base = brightwhite + highlight = brightblue + selection = black + alert = brightwhite + menubar = brightcyan + menu = brightcyan + disabled = brightcyan + accelerator = brightcyan + dialog = brightcyan + button = brightwhite + elevator = white + titlebar = white + scrollbar = black + borders = black + drivebox = brightwhite + driveicon = brightwhite + cursor = cyan + } + } +} + +associations = +{ + association = + { + program = EDIT + extension = TXT + } + association = + { + program = QBASIC /run + extension = BAS + } +} diff --git a/src/util/profile/krb5.conf b/src/util/profile/krb5.conf new file mode 100644 index 000000000..9b18a3993 --- /dev/null +++ b/src/util/profile/krb5.conf @@ -0,0 +1,12 @@ +[realms] + ATHENA.MIT.EDU = { + kdc = KERBEROS.MIT.EDU,88 + kdc = KERBEROS-1.MIT.EDU,88 + admin_server = KERBEROS.MIT.EDU + } + +[kdc] + port = 88 + +[libdefaults] + ticket_lifetime = 10 hours diff --git a/src/util/profile/prof_err.et b/src/util/profile/prof_err.et new file mode 100644 index 000000000..8686829e6 --- /dev/null +++ b/src/util/profile/prof_err.et @@ -0,0 +1,41 @@ +error_table prof + +error_code PROF_VERSION, "Profile version 0.0" + +# +# generated by prof_tree.c +# +error_code PROF_MAGIC_NODE, "Bad magic value in profile_node" +error_code PROF_NO_SECTION, "Profile section not found" +error_code PROF_NO_RELATION, "Profile relation not found" +error_code PROF_ADD_NOT_SECTION, + "Attempt to add a relation to node which is not a section" +error_code PROF_SECTION_WITH_VALUE, + "A profile section header has a non-zero value" +error_code PROF_BAD_LINK_LIST, "Bad linked list in profile structures" +error_code PROF_BAD_GROUP_LVL, "Bad group level in profile strctures" +error_code PROF_BAD_PARENT_PTR, + "Bad parent pointer in profile strctures" + +# +# generated by prof_parse.c +# + +error_code PROF_SECTION_NOTOP, "Profile section header not at top level" +error_code PROF_SECTION_SYNTAX, "Syntax error in profile section header" +error_code PROF_RELATION_SYNTAX, "Syntax error in profile relation" +error_code PROF_EXTRA_CBRACE, "Extra closing brace in profile" +error_code PROF_MISSING_OBRACE, "Missing open brace in profile" + +# +# generated by prof_init.c +# +error_code PROF_MAGIC_PROFILE, "Bad magic value in profile_t" +error_code PROF_MAGIC_SECTION, "Bad magic value in profile_section_t" +error_code PROF_TOPSECTION_ITER_NOSUPP, + "Iteration through all top level section not supported" +error_code PROF_INVALID_SECTION, "Invalid profile_section object" +error_code PROF_END_OF_SECTIONS, "No more sections" +error_code PROF_BAD_NAMESET, "Bad nameset passed to query routine" + +end diff --git a/src/util/profile/prof_file.c b/src/util/profile/prof_file.c new file mode 100644 index 000000000..8b2000819 --- /dev/null +++ b/src/util/profile/prof_file.c @@ -0,0 +1,76 @@ +/* + * prof_file.c ---- routines that manipulate an individual profile file. + */ + +#include +#include +#include +#include +#include + +#include "prof_int.h" + +errcode_t profile_open_file(filename, ret_prof) + const char *filename; + prf_file_t *ret_prof; +{ + prf_file_t prf; + errcode_t retval; + + prf = malloc(sizeof(struct _prf_file_t)); + if (!prf) + return ENOMEM; + memset(prf, 0, sizeof(struct _prf_file_t)); + prf->filename = malloc(strlen(filename)+1); + if (!prf->filename) { + free(prf); + return ENOMEM; + } + strcpy(prf->filename, filename); + + retval = profile_update_file(prf); + if (retval) { + profile_close_file(prf); + return retval; + } + + *ret_prof = prf; + return 0; +} + +errcode_t profile_update_file(prf) + prf_file_t prf; +{ + errcode_t retval; + struct stat st; + FILE *f; + + if (stat(prf->filename, &st)) + return errno; + if (st.st_mtime == prf->timestamp) + return 0; + if (prf->root) + profile_free_node(prf->root); + f = fopen(prf->filename, "r"); + if (f == NULL) + return errno; + retval = profile_parse_file(f, &prf->root); + fclose(f); + if (retval) + return retval; + prf->timestamp = st.st_mtime; + return 0; +} + +errcode_t profile_close_file(prf) + prf_file_t prf; +{ + if (prf->filename) + free(prf->filename); + if (prf->root) + profile_free_node(prf->root); + free(prf); + + return 0; +} + diff --git a/src/util/profile/prof_init.c b/src/util/profile/prof_init.c new file mode 100644 index 000000000..a09618b88 --- /dev/null +++ b/src/util/profile/prof_init.c @@ -0,0 +1,157 @@ +/* + * prof_init.c --- routines that manipulate the user-visible profile_t + * object. + */ + +#include +#include +#include +#include + +#include "prof_int.h" + +errcode_t profile_init(filenames, ret_profile) + const char **filenames; + profile_t *ret_profile; +{ + const char **fn; + profile_t profile; + prf_file_t new_file, last = 0; + errcode_t retval; + + profile = malloc(sizeof(struct _profile_t)); + if (!profile) + return ENOMEM; + memset(profile, 0, sizeof(struct _profile_t)); + profile->magic = PROF_MAGIC_PROFILE; + + for (fn = filenames; *fn; fn++) { + retval = profile_open_file(*fn, &new_file); + if (retval) { + profile_release(profile); + return retval; + } + if (last) + last->next = new_file; + else + profile->first_file = new_file; + last = new_file; + } + *ret_profile = profile; + return 0; +} + +void profile_release(profile) + profile_t profile; +{ + prf_file_t p, next; + + for (p = profile->first_file; p; p = next) { + next = p->next; + profile_close_file(p); + } + profile->magic = 0; + free(profile); +} + +struct string_list { + char **list; + int num; + int max; +}; + +static errcode_t init_list(list) + struct string_list *list; +{ + list->num = 0; + list->max = 10; + list->list = malloc(list->max * sizeof(char *)); + if (list->list == 0) + return ENOMEM; + list->list[0] = 0; + return 0; +} + +static void free_list(list) + struct string_list *list; +{ + char **cp; + + for (cp = list->list; *cp; cp++) + free(*cp); + free(list->list); + list->num = list->max = 0; + list->list = 0; +} + +static errcode_t add_to_list(list, str) + struct string_list *list; + const char *str; +{ + char *newstr; + + if (list->num+1 >= list->max) { + list->max += 5; + list->list = realloc(list->list, list->max * sizeof(char *)); + if (list->list == 0) + return ENOMEM; + } + newstr = malloc(strlen(str)+1); + if (newstr == 0) + return ENOMEM; + strcpy(newstr, str); + + list->list[list->num++] = newstr; + list->list[list->num] = 0; + return 0; +} + +/* + * XXX this version only works to get values from the first file. + * To do more than that means we have to implement some "interesting" + * code to do the section searching. + */ +errcode_t profile_get_values(profile, names, ret_values) + profile_t profile; + const char **names; + char ***ret_values; +{ + prf_file_t file; + errcode_t retval; + struct profile_node *parent, *section; + void *state; + char *value; + struct string_list values; + char **cpp; + + if (names == 0 || names[0] == 0 || names[1] == 0) + return PROF_BAD_NAMESET; + + init_list(&values); + + file = profile->first_file; + section = file->root; + + for (cpp = names; cpp[1]; cpp++) { + state = 0; + retval = profile_find_node_subsection(section, *cpp, + &state, 0, §ion); + if (retval) + goto cleanup; + } + + state = 0; + do { + retval = profile_find_node_relation(section, *cpp, &state, 0, &value); + if (retval) + goto cleanup; + add_to_list(&values, value); + } while (state); + + *ret_values = values.list; + return 0; +cleanup: + free_list(&values); + return retval; +} + diff --git a/src/util/profile/prof_int.h b/src/util/profile/prof_int.h new file mode 100644 index 000000000..2585277da --- /dev/null +++ b/src/util/profile/prof_int.h @@ -0,0 +1,119 @@ +/* + * prof-int.h + */ + +#include +#include "prof_err.h" + +#if defined(__STDC__) || defined(_WINDOWS) +#define PROTOTYPE(x) x +#else +#define PROTOTYPE(x) () +#endif + +typedef long errcode_t; + +/* + * This is the structure which stores the profile information for a + * particular configuration file. + */ +struct _prf_file_t { + errcode_t magic; + char *filename; + struct profile_node *root; + time_t timestamp; + int flags; + struct _prf_file_t *next; +}; + +typedef struct _prf_file_t *prf_file_t; + +/* + * This structure defines the high-level, user visible profile_t + * object, which is used as a handle by users who need to query some + * configuration file(s) + */ +struct _profile_t { + errcode_t magic; + prf_file_t first_file; +}; + +typedef struct _profile_t *profile_t; + +/* + * This structure defines the profile_section_t object, which is + * returned to the user when a section is searched. + */ +struct _profile_section_t { + errcode_t magic; + int top_lvl:1, top_lvl_search:1; + char *name; + void *state; + struct profile_node *parent, *sect; + profile_t profile; + prf_file_t file_ptr; +}; + +typedef struct _profile_section_t *profile_section_t; + +extern errcode_t profile_get + PROTOTYPE((const char *filename, prf_file_t *ret_prof)); + +extern errcode_t profile_update + PROTOTYPE((prf_file_t profile)); + +extern errcode_t profile_parse_file + PROTOTYPE((FILE *f, struct profile_node **root)); + +/* prof_tree.c */ + +extern void profile_free_node + PROTOTYPE((struct profile_node *relation)); + +extern errcode_t profile_create_node + PROTOTYPE((const char *name, const char *value, + struct profile_node **ret_node)); + +extern errcode_t profile_add_node + PROTOTYPE ((struct profile_node *section, + const char *name, const char *value, + struct profile_node **ret_node)); + +extern errcode_t profile_find_node_relation + PROTOTYPE ((struct profile_node *section, + const char *name, void **state, + char **ret_name, char **value)); + +extern errcode_t profile_find_node_subsection + PROTOTYPE ((struct profile_node *section, + const char *name, void **state, + char **ret_name, struct profile_node **subsection)); + +extern errcode_t profile_get_node_parent + PROTOTYPE ((struct profile_node *section, + struct profile_node **parent)); + +extern errcode_t profile_delete_node_relation + PROTOTYPE ((struct profile_node *section, const char *name)); + +/* prof_file.c */ + +extern errcode_t profile_open_file + PROTOTYPE ((const char *filename, prf_file_t *ret_prof)); + +extern errcode_t profile_update_file + PROTOTYPE ((prf_file_t profile)); + +extern errcode_t profile_close_file + PROTOTYPE ((prf_file_t profile)); + +/* prof_init.c */ + +errcode_t profile_init + PROTOTYPE ((const char **filenames, profile_t *ret_profile)); + +extern void profile_release + PROTOTYPE ((profile_t profile)); + + + diff --git a/src/util/profile/prof_parse.c b/src/util/profile/prof_parse.c new file mode 100644 index 000000000..7549c7647 --- /dev/null +++ b/src/util/profile/prof_parse.c @@ -0,0 +1,220 @@ +#include +#include +#include +#include +#include +#include + +#include "prof_int.h" + +#define SECTION_SEP_CHAR '/' + +#define STATE_INIT_COMMENT 1 +#define STATE_STD_LINE 2 +#define STATE_GET_OBRACE 3 + +struct parse_state { + int state; + int group_level; + struct profile_node *root_section; + struct profile_node *current_section; +}; + +static char *skip_over_blanks(cp) + char *cp; +{ + while (*cp && isspace(*cp)) + cp++; + return cp; +} + +void strip_line(line) + char *line; +{ + char *p; + + while (1) { + p = line + strlen(line) - 1; + if ((*p == '\n') || (*p == '\r')) + *p = 0; + else + break; + } +} + +static errcode_t parse_init_state(state) + struct parse_state *state; +{ + state->state = STATE_INIT_COMMENT; + state->group_level = 0; + + return profile_create_node("(root)", 0, &state->root_section); +} + +static errcode_t parse_std_line(line, state) + char *line; + struct parse_state *state; +{ + char *cp, ch, *tag, *value; + char *p; + unsigned int retval; + int do_subsection = 0; + void *iter = 0; + + if (*line == 0) + return 0; + if (line[0] == ';') + return 0; + strip_line(line); + cp = skip_over_blanks(line); + ch = *cp; + if (ch == 0) + return 0; + if (ch == '[') { + if (state->group_level > 0) + return PROF_SECTION_NOTOP; + cp++; + p = strchr(cp, ']'); + if (p == NULL) + return PROF_SECTION_SYNTAX; + *p = '\0'; + retval = profile_find_node_subsection(state->root_section, + cp, &iter, 0, + &state->current_section); + if (retval == PROF_NO_SECTION) { + retval = profile_add_node(state->root_section, + cp, 0, + &state->current_section); + if (retval) + return retval; + } else if (retval) + return retval; + + /* + * Finish off the rest of the line. + */ + cp = p+1; + if (*cp) + return PROF_SECTION_SYNTAX; + return 0; + } + if (ch == '}') { + if (state->group_level == 0) + return PROF_EXTRA_CBRACE; + retval = profile_get_node_parent(state->current_section, + &state->current_section); + if (retval) + return retval; + state->group_level--; + return 0; + } + /* + * Parse the relations + */ + p = strchr(cp, ' '); + if (!p) + return PROF_RELATION_SYNTAX; + *p = '\0'; + tag = cp; + cp = skip_over_blanks(p+1); + if (*cp != '=') + return PROF_RELATION_SYNTAX; + cp = skip_over_blanks(cp+1); + value = cp; + if (value[0] == 0) { + do_subsection++; + state->state = STATE_GET_OBRACE; + } + if (value[0] == '{' && value[1] == 0) + do_subsection++; + if (do_subsection) { + retval = profile_add_node(state->current_section, + tag, 0, &state->current_section); + if (retval) + return retval; + + state->group_level++; + return 0; + } + profile_add_node(state->current_section, tag, value, 0); + return 0; +} + +errcode_t parse_line(line, state) + char *line; + struct parse_state *state; +{ + char *cp; + + switch (state->state) { + case STATE_INIT_COMMENT: + if (line[0] != '[') + return 0; + state->state = STATE_STD_LINE; + case STATE_STD_LINE: + return parse_std_line(line, state); + case STATE_GET_OBRACE: + cp = skip_over_blanks(line); + if (*cp != '{') + return PROF_MISSING_OBRACE; + state->state = STATE_STD_LINE; + } + return 0; +} + +errcode_t profile_parse_file(f, root) + FILE *f; + struct profile_node **root; +{ + char buf[2048]; + int retval; + struct parse_state state; + + retval = parse_init_state(&state); + if (retval) + return retval; + while (!feof(f)) { + if (fgets(buf, sizeof(buf), f) == NULL) + break; + retval = parse_line(buf, &state); + if (retval) + return retval; + } + *root = state.root_section; + return 0; +} + +void dump_profile(root, level) + struct profile_node *root; + int level; +{ + int i; + struct profile_node *p; + void *iter; + long retval; + char *name, *value; + + iter = 0; + do { + retval = profile_find_node_relation(root, 0, &iter, + &name, &value); + if (retval) + break; + for (i=0; i < level; i++) + printf(" "); + printf("%s = '%s'\n", name, value); + } while (iter != 0); + + iter = 0; + do { + retval = profile_find_node_subsection(root, 0, &iter, + &name, &p); + if (retval) + break; + for (i=0; i < level; i++) + printf(" "); + printf("[%s]\n", name); + dump_profile(p, level+1); + } while (iter != 0); +} + diff --git a/src/util/profile/prof_section.c b/src/util/profile/prof_section.c new file mode 100644 index 000000000..bbcf65ae1 --- /dev/null +++ b/src/util/profile/prof_section.c @@ -0,0 +1,168 @@ +/* + * prof_section.c --- routines that manipulate the profile_section_t + * object + * + * XXX this file is still under construction. + */ + +#include +#include +#include +#include + +#include "prof_int.h" + +/* + * This routine frees a profile_section + */ +void profile_free_section(sect) + profile_section_t sect; +{ + if (sect->name) + free(sect->name); + sect->magic = 0; + free(sect); +} + +/* + * This routine creates a profile_section from its parent. If the + * parent is NULL, then a top-level profile section is created. + * + * Top-level profile sections are different from normal + * profile_sections in that top-level sections are agregated across + * multiple files, where as subsections are not. + */ +errcode_t profile_get_subsection(profile, parent, name, ret_name, + ret_section) + profile_t profile; + profile_section_t parent; + const char * name; + char ** ret_name; + profile_section_t *ret_section; +{ + profile_section_t section; + prf_file_t file; + errcode_t retval; + + section = malloc(sizeof(struct _profile_section_t)); + if (section == 0) + return ENOMEM; + memset(section, 0, sizeof(struct _profile_section_t)); + section->magic = PROF_MAGIC_SECTION; + section->name = malloc(strlen(name)+1); + if (section->name == 0) { + free(section); + return ENOMEM; + } + strcpy(section->name, name); + section->file_ptr = file = profile->first_file; + section->profile = profile; + + if (parent == 0) { + /* + * If parent is NULL, then we are creating a + * top-level section which hangs off the root. + * + * We make sure that the section exists in least one + * file. + */ + section->top_lvl = 1; + if (name == 0) + return PROF_TOPSECTION_ITER_NOSUPP; + while (file) { + retval = profile_find_node_subsection(file->root, + name, §ion->state, + ret_name, §ion->sect); + file = file->next; + if (retval == 0) + break; + if (retval == PROF_NO_SECTION) + continue; + profile_free_section(section); + return retval; + } + if (section->sect == 0 && file == 0) { + profile_free_section(section); + return PROF_NO_SECTION; + } + *ret_section = section; + return 0; + } + + + section->top_lvl = 0; + if (parent->top_lvl) { + section->top_lvl_search = 1; + + } else { + section->top_lvl_search = 0; + if (parent->sect == 0) { + profile_free_section(section); + return PROF_INVALID_SECTION; + } + section->parent = parent->sect; + retval = profile_find_node_subsection(parent->sect, + name, §ion->state, ret_name, §ion->sect); + if (retval) { + profile_free_section(section); + return retval; + } + } + *ret_section = section; + return 0; +} + +errcode_t profile_next_section(section, ret_name) + profile_section_t section; + char **ret_name; +{ + prf_file_t file; + errcode_t retval; + + if (section->top_lvl) + return PROF_END_OF_SECTIONS; + else { + if (section->sect == 0) + return PROF_INVALID_SECTION; + retval = profile_find_node_subsection(section->parent, + section->name, §ion->state, ret_name, §ion->sect); + if (retval == PROF_NO_SECTION) + retval = PROF_END_OF_SECTIONS; + return retval; + } +} + +errcode_t profile_get_relation(section, name, ret_values) + profile_section_t section; + const char *name; + char ***ret_values; +{ + prf_file_t file; + char **values; + int num_values; + int max_values; + char *value; + errcode_t retval; + + + max_values = 10; + values = malloc(sizeof(char *) * max_values); + + if (section->top_lvl) { + for (file = section->profile->first_file; file; + file = file->next) { + retval = profile_find_node_relation(file->root, + section->name, §ion->state, 0, &value); + if (retval) + continue; + + } + } else { + if (section->sect == 0) + return PROF_INVALID_SECTION; + } + return 0; +} + + + diff --git a/src/util/profile/prof_tree.c b/src/util/profile/prof_tree.c new file mode 100644 index 000000000..1dc701373 --- /dev/null +++ b/src/util/profile/prof_tree.c @@ -0,0 +1,334 @@ +/* + * prof_tree.c --- these routines maintain the parse tree of the + * config file. + * + * All of the details of how the tree is stored is abstracted away in + * this file; all of the other profile routines build, access, and + * modify the tree via the accessor functions found in this file. + * + * Each node may represent either a relation or a section header. + * + * A section header must have its value field set to 0, and may a one + * or more child nodes, pointed to by first_child. + * + * A relation has as its value a pointer to allocated memory + * containing a string. Its first_child pointer must be null. + * + */ + + +#include +#include +#include +#include +#include +#include + +#include "prof_int.h" + +struct profile_node { + errcode_t magic; + char *name; + char *value; + int group_level; + struct profile_node *first_child; + struct profile_node *parent; + struct profile_node *next, *prev; +}; + +#define CHECK_MAGIC(node) \ + if ((node)->magic != PROF_MAGIC_NODE) \ + return PROF_MAGIC_NODE; + +/* + * Free a node, and any children + */ +void profile_free_node(node) + struct profile_node *node; +{ + struct profile_node *child; + + if (node->magic != PROF_MAGIC_NODE) + return; + + if (node->name) + free(node->name); + if (node->value) + free(node->value); + for (child=node->first_child; child; child = child->next) + profile_free_node(child); + node->magic = 0; + + free(node); +} + +/* + * Create a node + */ +errcode_t profile_create_node(name, value, ret_node) + const char *name, *value; + struct profile_node **ret_node; +{ + struct profile_node *new; + + new = malloc(sizeof(struct profile_node)); + if (!new) + return ENOMEM; + memset(new, 0, sizeof(struct profile_node)); + new->name = malloc(strlen(name)+1); + if (new->name == 0) { + profile_free_node(new); + return ENOMEM; + } + strcpy(new->name, name); + if (value) { + new->value = malloc(strlen(value)+1); + if (new->value == 0) { + profile_free_node(new); + return ENOMEM; + } + strcpy(new->value, value); + } + new->magic = PROF_MAGIC_NODE; + + *ret_node = new; + return 0; +} + +/* + * This function verifies that all of the representation invarients of + * the profile are true. If not, we have a programming bug somewhere, + * probably in this file. + */ +errcode_t profile_verify_node(node) + struct profile_node *node; +{ + struct profile_node *p, *last; + + CHECK_MAGIC(node); + + if (node->value && node->first_child) + return PROF_SECTION_WITH_VALUE; + + last = 0; + for (p = node->first_child; p; last = p, p = p->next) { + if (p->prev != last) + return PROF_BAD_LINK_LIST; + if (last && (last->next != p)) + return PROF_BAD_LINK_LIST; + if (node->group_level != p->group_level+1) + return PROF_BAD_GROUP_LVL; + if (p->parent != node) + return PROF_BAD_PARENT_PTR; + profile_verify_node(p); + } + return 0; +} + +/* + * Add a node to a particular section + */ +errcode_t profile_add_node(section, name, value, ret_node) + struct profile_node *section; + const char *name, *value; + struct profile_node **ret_node; +{ + errcode_t retval; + struct profile_node *p, *last, *new; + int cmp = -1; + + CHECK_MAGIC(section); + + if (section->value) + return PROF_ADD_NOT_SECTION; + + for (p=section->first_child, last = 0; p; last = p, p = p->next) { + cmp = strcmp(p->name, name); + if (cmp >= 0) + break; + } + retval = profile_create_node(name, value, &new); + if (retval) + return retval; + new->group_level = section->group_level+1; + new->parent = section; + if (cmp == 0) { + do { + last = p; + p = p->next; + } while (p && strcmp(p->name, name) == 0); + } + new->prev = last; + if (last) + last->next = new; + else + section->first_child = new; + if (p) + new->next = p; + if (ret_node) + *ret_node = new; + return 0; +} + +/* + * Iterate through the section, returning the relations which match + * the given name. If name is NULL, then interate through all the + * relations in the section. The first time this routine is called, + * the state pointer must be null. When this profile_find_node_relatioon() + * returns, if the state pointer is non-NULL, then this routine should + * be called again. + * + * The returned character string in value points to the stored + * character string in the parse string. Before this string value is + * returned to a calling application (profile_find_node_relatioon is not an + * exported interface), it should be strdup()'ed. + */ +errcode_t profile_find_node_relation(section, name, state, ret_name, value) + struct profile_node *section; + const char *name; + void **state; + char **ret_name, **value; +{ + struct profile_node *p; + + CHECK_MAGIC(section); + p = *state; + if (p) { + CHECK_MAGIC(p); + } else + p = section->first_child; + + while (p) { + if (((name == 0) || (strcmp(p->name, name) == 0)) && + p->value) { + *value = p->value; + if (ret_name) + *ret_name = p->name; + break; + } + p = p->next; + } + if (p == 0) { + *state = 0; + return PROF_NO_RELATION; + } + /* + * OK, we've found one match; now let's try to find another + * one. This way, if we return a non-zero state pointer, + * there's guaranteed to be another match that's returned. + */ + p = p->next; + while (p) { + if (((name == 0) || (strcmp(p->name, name) == 0)) && + p->value) + break; + p = p->next; + } + *state = p; + return 0; +} + +/* + * Iterate through the section, returning the subsections which match + * the given name. If name is NULL, then interate through all the + * subsections in the section. The first time this routine is called, + * the state pointer must be null. When this profile_find_node_subsection() + * returns, if the state pointer is non-NULL, then this routine should + * be called again. + */ +errcode_t profile_find_node_subsection(section, name, state, ret_name, + subsection) + struct profile_node *section; + const char *name; + void **state; + char **ret_name; + struct profile_node **subsection; +{ + struct profile_node *p; + + CHECK_MAGIC(section); + p = *state; + if (p) { + CHECK_MAGIC(p); + } else + p = section->first_child; + + while (p) { + if (((name == 0) || (strcmp(p->name, name) == 0)) && + (p->value == 0)) { + *subsection = p; + if (ret_name) + *ret_name = p->name; + break; + } + p = p->next; + } + if (p == 0) { + *state = 0; + return PROF_NO_SECTION; + } + /* + * OK, we've found one match; now let's try to find another + * one. This way, if we return a non-zero state pointer, + * there's guaranteed to be another match that's returned. + */ + p = p->next; + while (p) { + if (((name == 0) || (strcmp(p->name, name) == 0)) + && (p->value == 0)) + break; + p = p->next; + } + *state = p; + return 0; +} + +/* + * This function deletes a relation from a section. Subsections are + * not deleted; if those need to be deleted, they must be done so manually. + */ +errcode_t profile_delete_node_relation(section, name) + struct profile_node *section; + const char *name; +{ + struct profile_node *p, *next; + + for (p = section->first_child; p; p = p->next) { + if ((strcmp(p->name, name) == 0) && p->value) + break; + } + if (p == 0) + return PROF_NO_RELATION; + /* + * Now we start deleting the relations... if we find a + * subsection with the same name, delete it and keep going. + */ + while (p && (strcmp(p->name, name) == 0)) { + if (p->value == 0) { + p = p->next; + continue; + } + if (p->prev) + p->prev->next = p->next; + else + section->first_child = p->next; + next = p->next; + if (p->next) + p->next->prev = p; + profile_free_node(p); + p = next; + } + return 0; +} + +/* + * This function returns the parent of a particular node. + */ +errcode_t profile_get_node_parent(section, parent) + struct profile_node *section, **parent; +{ + *parent = section->parent; + return 0; +} + + diff --git a/src/util/profile/profile.h.in b/src/util/profile/profile.h.in new file mode 100644 index 000000000..d157d2262 --- /dev/null +++ b/src/util/profile/profile.h.in @@ -0,0 +1,20 @@ +/* + * profile.h + */ + +typedef struct _profile_t *profile_t; + +#if defined(__STDC__) || defined(_WINDOWS) +#define PROTOTYPE(x) x +#else +#define PROTOTYPE(x) () +#endif + +extern long profile_init + PROTOTYPE ((const char **filenames, profile_t *ret_profile)); + +extern void profile_release + PROTOTYPE ((profile_t profile)); + +extern long profile_get_values + PROTOTYPE ((profile_t profile, const char **names, char ***ret_values)); diff --git a/src/util/profile/test.ini b/src/util/profile/test.ini new file mode 100644 index 000000000..505c4a1d2 --- /dev/null +++ b/src/util/profile/test.ini @@ -0,0 +1,46 @@ +this is a comment. Everything up to the first square brace is ignored. + +[test section 2] + child_section2 = one + child_section2 = { + child = slick + child = harry + child = john + } + child_section2 = foo + +[realms] +ATHENA.MIT.EDU = { + server = KERBEROS.MIT.EDU:88 + server = KERBEROS1.MIT.EDU:750 + server = KERBEROS2.MIT.EDU:750 + admin = KERBEROS.MIT.EDU + etype = DES-MD5 +} + + + +[test section 1] + foo = "bar" + +[test section 2] + quux = "bar" + frep = bar + kappa = alpha + beta = epsilon + +[test section 1] + bar = foo + foo = bar2 + quux = zap + foo = bar3 + child_section = { + child = slick + child = harry + child = john + } + child_section = foo + + + + diff --git a/src/util/profile/test_parse.c b/src/util/profile/test_parse.c new file mode 100644 index 000000000..fd81d1d16 --- /dev/null +++ b/src/util/profile/test_parse.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include + +#include "profile.h" +#include "com_err.h" + +int main(argc, argv) + int argc; + char **argv; +{ + struct profile_relation *root; + unsigned long retval; + FILE *f; + + initialize_prof_error_table(); + if (argc != 2) { + fprintf(stderr, "%s: Usage \n", argv[0]); + exit(1); + } + + f = fopen(argv[1], "r"); + if (!f) { + perror(argv[1]); + exit(1); + } + + retval = profile_parse_file(f, &root); + if (retval) { + printf("profile_parse_file error %s\n", error_message(retval)); + return 0; + } + fclose(f); + + printf("\n\nDebugging dump.\n"); + dump_profile(root, 0); + + profile_free_node(root); + return 0; +} diff --git a/src/util/profile/test_profile.c b/src/util/profile/test_profile.c new file mode 100644 index 000000000..83768f30a --- /dev/null +++ b/src/util/profile/test_profile.c @@ -0,0 +1,45 @@ +/* + * test_profile.c --- testing program for the profile routine + */ + +#include +#include +#include + +#include "profile.h" +#include "com_err.h" + +int main(argc, argv) + int argc; + char **argv; +{ + profile_t profile; + long retval; + const char *filenames[2]; + char **values, **cpp; + + filenames[0] = argv[1]; + filenames[1] = 0; + + initialize_prof_error_table(); + + retval = profile_init(filenames, &profile); + if (retval) { + com_err(argv[0], retval, "while initializing profile"); + exit(1); + } + retval = profile_get_values(profile, argv+2, &values); + if (retval) { + com_err(argv[0], retval, "while getting values"); + exit(1); + } + for (cpp = values; *cpp; cpp++) { + printf("%s\n", *cpp); + free(*cpp); + } + free(values); + profile_release(profile); + exit(0); +} + + -- 2.26.2