Initial checkin of the profile library
authorTheodore Tso <tytso@mit.edu>
Thu, 20 Apr 1995 14:57:45 +0000 (14:57 +0000)
committerTheodore Tso <tytso@mit.edu>
Thu, 20 Apr 1995 14:57:45 +0000 (14:57 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@5382 dc483132-0cff-0310-8789-dd5450dbe970

16 files changed:
src/util/profile/.cvsignore [new file with mode: 0644]
src/util/profile/Makefile.in [new file with mode: 0644]
src/util/profile/configure.in [new file with mode: 0644]
src/util/profile/dosshell.ini [new file with mode: 0644]
src/util/profile/krb5.conf [new file with mode: 0644]
src/util/profile/prof_err.et [new file with mode: 0644]
src/util/profile/prof_file.c [new file with mode: 0644]
src/util/profile/prof_init.c [new file with mode: 0644]
src/util/profile/prof_int.h [new file with mode: 0644]
src/util/profile/prof_parse.c [new file with mode: 0644]
src/util/profile/prof_section.c [new file with mode: 0644]
src/util/profile/prof_tree.c [new file with mode: 0644]
src/util/profile/profile.h.in [new file with mode: 0644]
src/util/profile/test.ini [new file with mode: 0644]
src/util/profile/test_parse.c [new file with mode: 0644]
src/util/profile/test_profile.c [new file with mode: 0644]

diff --git a/src/util/profile/.cvsignore b/src/util/profile/.cvsignore
new file mode 100644 (file)
index 0000000..e8c05a6
--- /dev/null
@@ -0,0 +1 @@
+configure
diff --git a/src/util/profile/Makefile.in b/src/util/profile/Makefile.in
new file mode 100644 (file)
index 0000000..0537db8
--- /dev/null
@@ -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 (file)
index 0000000..364e45e
--- /dev/null
@@ -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 (file)
index 0000000..cec96ec
--- /dev/null
@@ -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 (file)
index 0000000..9b18a39
--- /dev/null
@@ -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 (file)
index 0000000..8686829
--- /dev/null
@@ -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 (file)
index 0000000..8b20008
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * prof_file.c ---- routines that manipulate an individual profile file.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#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 (file)
index 0000000..a09618b
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * prof_init.c --- routines that manipulate the user-visible profile_t
+ *     object.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#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, &section);
+       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 (file)
index 0000000..2585277
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * prof-int.h
+ */
+
+#include <time.h>
+#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 (file)
index 0000000..7549c76
--- /dev/null
@@ -0,0 +1,220 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+
+#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 (file)
index 0000000..bbcf65a
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * prof_section.c --- routines that manipulate the profile_section_t
+ *     object
+ *
+ * XXX this file is still under construction.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#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, &section->state,
+                               ret_name, &section->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, &section->state, ret_name, &section->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, &section->state, ret_name, &section->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, &section->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 (file)
index 0000000..1dc7013
--- /dev/null
@@ -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 <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+
+#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 (file)
index 0000000..d157d22
--- /dev/null
@@ -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 (file)
index 0000000..505c4a1
--- /dev/null
@@ -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 (file)
index 0000000..fd81d1d
--- /dev/null
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+
+#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 <filename>\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 (file)
index 0000000..83768f3
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * test_profile.c --- testing program for the profile routine
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#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);
+}
+    
+