Initial revision
authorAdam Dickmeiss <adam@indexdata.dk>
Thu, 9 Feb 1995 17:27:10 +0000 (17:27 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Thu, 9 Feb 1995 17:27:10 +0000 (17:27 +0000)
19 files changed:
Makefile [new file with mode: 0644]
include/gw-log.h [new file with mode: 0644]
include/gw-res.h [new file with mode: 0644]
include/iso2709.h [new file with mode: 0644]
include/iso2709p.h [new file with mode: 0644]
res+log/ChangeLog [new file with mode: 0644]
res+log/Makefile [new file with mode: 0644]
res+log/README [new file with mode: 0644]
res+log/adam.res [new file with mode: 0644]
res+log/big.res [new file with mode: 0644]
res+log/default.res [new file with mode: 0644]
res+log/gw-log-test.c [new file with mode: 0644]
res+log/gw-log.c [new file with mode: 0644]
res+log/gw-res-test.c [new file with mode: 0644]
res+log/gw-res.c [new file with mode: 0644]
res+log/gw-resp.h [new file with mode: 0644]
util/Makefile [new file with mode: 0644]
util/iso2709.c [new file with mode: 0644]
util/iso2709dump.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..e5bee67
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,55 @@
+# Top level Makefile for Email gateway.
+# Europagate, 1994-1995.
+#
+# $Log: Makefile,v $
+# Revision 1.1  1995/02/09 17:27:10  adam
+# Initial revision
+#
+SHELL=/bin/sh
+MAKE=make
+SUBDIR=res+log util
+CFLAGS=-Wall -g -pedantic -ansi 
+CC=gcc
+
+all:
+       for i in $(SUBDIR); do cd $$i; if $(MAKE) CFLAGS="$(CFLAGS)" CC="$(CC)"; then cd ..; else exit 1; fi; done
+
+dep depend:
+       for i in $(SUBDIR); do cd $$i; if $(MAKE) depend; then cd ..; else exit 1; fi; done
+
+clean:
+       rm -f lib/*
+       for i in $(SUBDIR); do (cd $$i; $(MAKE) clean); done
+
+cleanup:
+       rm -f lib `find $(SUBDIR) -name "*.[oa]" -print`
+       rm -f `find $(SUBDIR) -name "core" -print`
+       rm -f `find $(SUBDIR) -name "errlist" -print`
+       rm -f `find $(SUBDIR) -name "a.out" -print`
+
+distclean: cleanup clean
+       for i in $(SUBDIR); do (cd $$i; \
+               mv Makefile Makefile.old; \
+               sed '/^#Depend/q' <Makefile.old >Makefile; \
+               rm Makefile.old); done
+
+usedepend1:
+       for i in $(SUBDIR); do (cd $$i; \
+               mv Makefile Makefile.tmp; \
+               sed 's/^if/#if/' <Makefile.tmp|sed 's/^include/#include/'| \
+               sed 's/^endif/#endif/' | \
+               sed 's/^depend: depend2/depend: depend1/g' >Makefile; \
+               rm Makefile.tmp); done
+
+usedepend2:
+       for i in $(SUBDIR); do (cd $$i; \
+               mv Makefile Makefile.tmp; \
+               sed '/^#Depend/q' <Makefile.tmp| \
+               sed 's/^#if/if/' |sed 's/^#include/include/'| \
+               sed 's/^#endif/endif/' | \
+               sed 's/^depend: depend1/depend: depend2/g' >Makefile; \
+               rm Makefile.tmp); done
+
+wc:
+       wc `find . -name '*.[ch]'`
+       
diff --git a/include/gw-log.h b/include/gw-log.h
new file mode 100644 (file)
index 0000000..d74c1fb
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+   gw-log.h: Logging facilities.
+
+   Europagate, 1994-1995.
+
+   $Log: gw-log.h,v $
+   Revision 1.1  1995/02/09 17:27:11  adam
+   Initial revision
+
+
+   Initial:       Dec  7, 94 (Adam Dickmeiss)
+   Last update:   Dec 13, 94 (Adam Dickmeiss)
+ */
+
+#ifndef GW_LOG_H
+#define GW_LOG_H
+/* The log level is an unsigned integer value with at least 16 bits */
+
+/* The log levels are defined below */
+#define GW_LOG_FATAL 0x01
+#define GW_LOG_WARN  0x02
+#define GW_LOG_ACCT  0x04
+#define GW_LOG_STAT  0x08
+
+/* All debug levels */
+#define GW_LOG_DEBUG 0xfff0
+/* Individual debug levels, x sould be in range 0-11 */
+#define GW_LOG_DEBUGN(x) (0x10<<(x))
+
+/* All levels on / All levels except debugging */
+#define GW_LOG_ALL   0xffff
+#define GW_LOG_DEFAULT 0x0f
+
+void gw_log_init (const char *app_name);
+/*
+   Initialises the log-system. Application name is given by 'app_name' - 
+   could be specified as argv[0]. The application name should not
+   contain blanks! 
+
+   All log messages are directed to stderr on return from this function. 
+   Override this behaviour by using the gw_log_file function.
+   
+   The log level is set to GW_LOG_DEFAULT. Override this with the
+   gw_log_level function.
+
+   The session id is set to 0. Use gw_log_session to change this.
+ */
+
+void gw_log_level (unsigned level);
+/*
+   Sets the log to 'level' by using the GW_LOG_xxxx masks as described
+   above.
+ */
+
+void gw_log_session (int session);
+/*
+   Sets the session id to 'session'.
+ */
+
+int gw_log_file (unsigned level, const char *fname);
+/*
+   Specifies that output given by 'level' should be appended to file 'fname'.
+   Thus, all log messages can be written to one file or several files.
+   If 'level' is GW_LOG_ALL all output is appended to the same file.
+   If 'fname' is NULL it means that the output is written to stderr.
+   If 'fname' is "" it means the output is written to stdout.
+
+   This function returns 0 on success; -1 on failure.
+ */ 
+
+int gw_log (unsigned level, const char *event_type, const char *format, ...);
+/*
+   Append log message to one or more files. The value of parameter
+   'level' and the value given by the last gw_log_level call are bitwise
+   AND'ed. This value represents the log level for this message. 
+   If this value is non-zero the 'event_type' and 'format' are used to 
+   create the log entries which are appended to the log files specified by 
+   the gw_log_file call(s).
+
+   The 'event_type' should not contain blanks.
+   This function returns 0 on success; -1 on failure.
+ */
+
+char *gw_strdup (const char *s);
+/*
+   Works as strdup, which is not defined by ANSI.
+ */
+
+
+/* log file format:
+   <appname> <session> <date> <level> <type> <parameter>
+
+   Assuming that a 'token' is separated by one or more blanks we have:
+
+   <appname>   one token
+   <session>   one token
+   <date>      five tokens (Tue Dec  6 11:34:21 1994)
+   <level>     one token
+   <type>      one token
+
+   <parameter> zero or more tokens.
+ */
+#endif
diff --git a/include/gw-res.h b/include/gw-res.h
new file mode 100644 (file)
index 0000000..35f654d
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+   gw-res.h: Resource management.
+
+   Europagate, 1994-1995.
+
+   $Log: gw-res.h,v $
+   Revision 1.1  1995/02/09 17:27:11  adam
+   Initial revision
+
+
+   Initial:       Dec  7, 94 (Adam Dickmeiss)
+   Last update:   Dec 13, 94 (Adam Dickmeiss)
+ */
+#ifndef GW_RES_H
+#define GW_RES_H
+
+typedef struct Gw_res_info *GwRes;   /* Gateway resource handle */
+
+GwRes gw_res_init (void);
+/*
+    A resource handle is returned by this function describing
+    the empty resource.
+ */
+
+void gw_res_close (GwRes id);
+/*
+    The resources described by 'id' are freed. No further references
+    to 'id' are allowed.
+ */
+
+int gw_res_merge (GwRes id, const char *filename);
+/*
+    The resources described by 'id' are merged by the contents of 
+    'filename'. If a resource is duplicated (in both resources 'id' and
+    the file) the resource is set to the value specified in 'filename'.
+
+    This function returns 0 on success; -1 on failure ('filename'
+    could not be read)
+ */
+
+const char *gw_res_get (GwRes id, const char *name, const char *def);
+/*
+    The resource with name 'name' is checked in the resources represented
+    by 'id'. If the resource is present a pointer to the value (null-
+    terminated string) is returned. If the value is not present the 
+    value of 'def' is returned.
+ */
+
+int gw_res_put (GwRes id, const char *name, const char *value, 
+                const char *fname);
+/*
+    Change a resource - modify if it exists - add if not already
+    there. The resource will have impact on the file name 'fname'.
+    Use gw_res_commit (see below) to actually write to the
+    resource file.
+ */
+
+int gw_res_commit (GwRes id, const char *fname);
+/*
+    Rewrite the resource file 'fname'. If resources are modified/added
+    then these will be written now.
+ */
+
+
+int gw_res_trav (GwRes id, const char *fname, void (*tf)(const char *name,
+                                                        const char *value));
+/*
+    Traverse resources associated with file 'fname'. For each resource
+    the handler 'tf' is invoked with name and value.
+ */
+
+/*
+   GwRes file format.
+
+   A resource name must begin on column 0 on a  line. The name is followed 
+   by colon. The value of the resource comes after the colon. A value may 
+   span over several lines. Subsequent value lines are preceeded by one or 
+   more blanks (tab/space). Empty/blank lines are ignored. Lines beginning 
+   with # are treated as comments. 
+
+   Example
+    # Comment. Ignored
+   
+    # Single line resource
+    MaxSize: 1000
+    # Multi line resource
+    FatalMsg: A serious error
+     occured. Aborting.
+    # Yet another (danish):
+    Warning: Advarsel, taenk
+         dig om - inden du foretager dig noget.
+
+   The FatalMsg resource has the value "A serious error occured. Aborting.", 
+   and the Warning resource has the value 
+   "Advarsel, taenk dig om - inden du foretager dig noget." Note
+   that all blanks used to separate subsequent lines are treated as exactly 
+   one blank.
+*/
+#endif
diff --git a/include/iso2709.h b/include/iso2709.h
new file mode 100644 (file)
index 0000000..a327e06
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+   Record management
+
+   Europagate, 1994-1995.
+
+   $Log: iso2709.h,v $
+   Revision 1.1  1995/02/09 17:27:11  adam
+   Initial revision
+
+ */
+
+typedef struct iso2709_rec *Iso2709Rec;
+
+char *iso2709_read (FILE *inf);
+Iso2709Rec iso2709_cvt (const char *buf);
diff --git a/include/iso2709p.h b/include/iso2709p.h
new file mode 100644 (file)
index 0000000..0c8472f
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+   Record management
+
+   Europagate, 1994-1995.
+
+   $Log: iso2709p.h,v $
+   Revision 1.1  1995/02/09 17:27:11  adam
+   Initial revision
+
+ */
+
+#include <iso2709.h>
+
+struct iso2709_field {
+    char *indicator;
+    char *identifier;
+    char *data;
+    struct iso2709_field *next;
+};
+
+struct iso2709_dir {
+    char tag[4];
+    int  length;
+    int  offset;
+    struct iso2709_dir *next;
+    struct iso2709_field *fields;
+};
+
+struct iso2709_rec {
+    int  record_length;
+    char record_status[2];
+    char implementation_codes[5];
+    int  indicator_length;
+    int  identifier_length;
+    int  base_address;
+    char user_systems[4];
+
+    int  length_data_entry;
+    int  length_starting;
+    int  length_implementation;
+    char future_use[2];
+
+    struct iso2709_dir *directory;
+};
+
+#define ISO2709_FS 036
+#define ISO2709_IDFS 037
diff --git a/res+log/ChangeLog b/res+log/ChangeLog
new file mode 100644 (file)
index 0000000..ddf4468
--- /dev/null
@@ -0,0 +1,10 @@
+#$Log: ChangeLog,v $
+#Revision 1.1  1995/02/09 17:27:10  adam
+#Initial revision
+#
+#
+Dec 19 1994
+       Advisory file locking used in merge/commit functions.
+       Makefile edited.
+Dec 14 1994
+       First version
diff --git a/res+log/Makefile b/res+log/Makefile
new file mode 100644 (file)
index 0000000..364cdb2
--- /dev/null
@@ -0,0 +1,53 @@
+# Makefile for resource management/logging facilities.
+# Europagate, 1994-1995.
+#
+# $Log: Makefile,v $
+# Revision 1.1  1995/02/09 17:27:10  adam
+# Initial revision
+#
+SHELL=/bin/sh
+INCLUDE=-I../include
+CFLAGS=-Wall -pedantic -ansi
+CPP=gcc -E
+CC=gcc
+TPROG1=gw-log-test
+TPROG2=gw-res-test
+LIB=../lib/libres+log.a
+PO=gw-log.o gw-res.o
+DEFS=$(INCLUDE)
+
+all: $(TPROG1) $(TPROG2)
+
+$(TPROG1): $(TPROG1).o $(LIB) 
+       $(CC) $(CFLAGS) -o $(TPROG1) $(TPROG1).o $(LIB)
+
+$(TPROG2): $(TPROG2).o $(LIB) 
+       $(CC) $(CFLAGS) -o $(TPROG2) $(TPROG2).o $(LIB) 
+
+$(LIB): $(PO)
+       rm -f $(LIB)
+       ar qc $(LIB) $(PO)
+       ranlib $(LIB)
+
+.c.o:
+       $(CC) -c $(DEFS) $(CFLAGS) $<
+
+clean:
+       rm -f *.log *.[oa] $(TPROG1) $(TPROG2) core mon.out gmon.out errlist *~
+
+depend: depend2
+
+depend1:
+       mv Makefile Makefile.tmp
+       sed '/^#Depend/q' <Makefile.tmp >Makefile
+       $(CPP) $(INCLUDE) -M *.c >>Makefile
+       -rm Makefile.tmp
+
+depend2:
+       $(CPP) $(INCLUDE) -M *.c >.depend       
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+#Depend --- DOT NOT DELETE THIS LINE
diff --git a/res+log/README b/res+log/README
new file mode 100644 (file)
index 0000000..ca62fdb
--- /dev/null
@@ -0,0 +1,31 @@
+Wed Dec 14 1994
+
+Resource management + logging system, Europagate 1994
+
+File           Description
+
+Makefile       Makefile - use 'make all' / 'make clean'
+gw-res.c       Resource management - implementation.
+gw-resp.h      Resource management - private header file.
+gw-res.h       Resource management - public header file.
+gw-log.c       Logging system - implementation.
+gw-log.h       Logging system - public header file.
+gw-log-test.c  Small test example that uses the logging system.
+gw-res-test.c  Small interactive test program that uses the resources.
+*.res          Some resource files.
+
+A 'make all' will create:
+
+libres+log.a   Library with logging+resource functions.
+gw-log-test    Small test program that uses the logging system. 
+gw-res-test    Small test program that uses both logging+resource.
+               Starting the program with no parameters will invoke
+               a small interactive resource management shell.
+
+Normal applications should include gw-res.h and gw-log.h. Link
+with the library libres+log.a.
+
+The API is described in gw-res.h and gw-log.h.
+
+Adam Dickmeiss
+
diff --git a/res+log/adam.res b/res+log/adam.res
new file mode 100644 (file)
index 0000000..07310dc
--- /dev/null
@@ -0,0 +1,3 @@
+# $Id: adam.res,v 1.1 1995/02/09 17:27:11 adam Exp $
+a: 3
+c: 45
diff --git a/res+log/big.res b/res+log/big.res
new file mode 100644 (file)
index 0000000..c878d8b
--- /dev/null
@@ -0,0 +1,354 @@
+# Personal X setup : ~/.Xdefaults, ~/.Xresources
+# Adam Dickmeiss
+# $Id: big.res,v 1.1 1995/02/09 17:27:11 adam Exp $
+
+# This file specifies the default resources used by Emacs.
+# Colors and backgrounds.
+# ======================
+# The contrasts of these colors will cause them to map to the appropriate
+# one of "black" or "white" on monochrome systems.
+# 
+# The valid color names on your system can be found by looking in the file
+# `rgb.txt', usually found in /usr/lib/X11/ or /usr/openwin/lib/X11/.
+
+
+# Set the foreground and background colors.  This will apply to all
+# elements of Emacs, except those that specifically override them.
+# Emacs*Foreground:                    Black
+# Emacs*Background:                    #d3d3d3
+
+# Set the color of the text cursor.
+
+# Set the color of the mouse pointer.
+
+# Set the menubar colors.  This overrides the default foreground and
+# background colors specified above.
+
+# Specify the colors of popup menus.
+
+# Specify the colors of the various sub-widgets of the dialog boxes.
+# #A5C0C1 is a shade of blue
+
+
+# If you want to turn off scrollbars, or change the default pixel width
+# of the scrollbars, do it like this (0 width means no scrollbars):
+# 
+# 
+# To change it for a particular screen, do this:
+# 
+# Emacs*SCREEN-NAME.scrollBarWidth: 0
+
+
+# To have the Motif scrollbars on the left instead of the right, do this:
+# 
+# Emacs*scrollBarPlacement: BOTTOM_LEFT
+# 
+# The default is BOTTOM_RIGHT.  There is no way to change the placement of
+# the Athena scrollbars (all Athena programs put the scrollbars on the left.)
+
+
+# Fonts.
+# ======
+# Emacs requires the use of XLFD (X Logical Font Description) format font
+# names, which look like
+# 
+#      *-courier-medium-r-*-*-*-120-*-*-*-*-*-*
+# 
+# if you use any of the other, less strict font name formats, some of which
+# look like
+#              lucidasanstypewriter-12
+# and          fixed
+# and          9x13
+# 
+# then Emacs won't be able to guess the names of the bold and italic versions.
+# All X fonts can be referred to via XLFD-style names, so you should use those
+# forms.  See the man pages for X(1), xlsfonts(1), and xfontsel(1).
+
+
+# The default font for the text area of lemacs is chosen at run-time
+# by lisp code which tries a number of different possibilities in order
+# of preference.  If you wish to override it, use this:
+# 
+# Emacs*default.attributeFont:  -*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*
+
+# If you choose a font which does not have an italic version, you can specify
+# some other font to use for it here:
+# 
+#
+# And here is how you would set the background color of the `highlight' face,
+# but only on the screen named `debugger':
+# 
+# 
+# See the NEWS file (C-h n) for a more complete description of the resource
+# syntax of faces.
+
+
+# Font of the menubar and pop-up menus.
+# Note that these do not use the `face' syntax, since they are outside the
+# domain of Emacs proper, and in the domain of the X toolkit widgets:
+# 
+
+# Font in the Motif dialog boxes.
+# (Motif uses `fontList' while most other things use `font' - if you don't
+# know why you probably don't want to.)
+# 
+
+
+# Dialog box translations.
+# =======================
+
+# This accelerator binds <return> in a dialog box to <activate> on button1
+
+# Translations to make the TextField widget behave more like Emacs
+
+# With the Emacs typeahead it's better to not have space be bound to
+# ArmAndActivate() for buttons that appear in dialog boxes.  This is
+# not 100% Motif compliant but the benefits far outweight the
+# compliancy problem.  
+#
+# Mosaic defaults
+#
+
+
+
+
+
+
+
+xfig*customization: -color
+XRn.nntpServer: puff
+XRn*index*Background: gray35
+XRn*index*Foreground: white
+XRn*articleText*Background: gray35
+XRn*articleText*Foreground: white
+XRn*indexinfo*Background: #5f9ea0
+XRn*textinfo*Background: #5f9ea0
+XRn*Foreground: black
+XRn*Background: #d3d3d3
+XRn*Command.font: 8x13
+XRn.Geometry: 680x600
+Scrollbar.JumpCursor: True
+Seyon.modem: /dev/ttyS3
+Seyon*Foreground: black
+Seyon*Background: #5f9ea0
+Seyon*Label.Background: #d3d3d3
+Seyon*Command.Background: #d3d3d3
+XSysinfo*BarGauge.background: white
+XSysinfo*background: #537483
+XSysinfo*font: fixed
+Clock*hour: yellow
+Clock*jewel: indianred1
+Clock*minute: yellow
+xbiff*background: #537483
+xbiff*foreground: black
+XTerm*SimpleMenu*Background: #d3d3d3
+XTerm*SimpleMenu*Foreground: black
+XTerm*Background: gray35
+XTerm*Foreground: white
+XTerm*cursorColor: IndianRed1
+XTerm*ScrollLines: 400
+Seyon.vt100*Foreground: white
+Seyon.vt100*Background: gray36
+Seyon.vt100*ScrollLines: 400
+Xmris.Throw: return
+Xmris.Right: s
+Xmris.Left: a
+Xmris.Down: comma
+Xmris.Up: l
+OpenWindows.AutoRaiseDelay: 200000
+OpenWindows.ShowResizeGeometry: True
+OpenWindows.SetInput: followmouse
+OpenWindows.VirtualBackgroundColor: Tan
+OpenWindows.KeyboardCommands: Basic
+OpenWindows.IconLocation: left
+OpenWindows.ScrollbarPlacement: right
+OpenWindows.Use3DFrames: True
+OpenWindows.WindowColor: #98bfbf
+OpenWindows.Beep: notices
+OpenWindows.MinimalDecor: xclock xsysinfo olvwm
+OpenWindows.VirtualFontColor: Black
+OpenWindows.Use3DResize: False
+OpenWindows.SelectDisplaysMenu: False
+OpenWindows.ShowMoveGeometry: True
+OpenWindows.AutoRaise: false
+OpenWindows.MultiClickTimeout: 4
+OpenWindows.InvertFocusHighlighting: true
+OpenWindows.DragRightDistance: 100
+OpenWindows.PopupJumpCursor: True
+OpenWindows.WorkspaceColor: #7f7f7f
+OpenWindows.VirtualForegroundColor: White
+OpenWindows.PaintWorkSpace: false
+olvwm.BackGround: green
+olvwm.Foreground: black
+olvwm.VirtualDesktop: 3x2
+olvwm.VirtualGeometry: +810+0
+*VT100.Translations: #override <Key>F1: string(0x01) string("1")\n\ <Key>F2:
+ string(0x01) string("2")\n
+*customization: -color
+*basicLocale: C
+*numeric: C
+*inputLang: C
+*displayLang: C
+*timeFormat: C
+Emacs*Foreground: white
+Emacs*Background: gray35
+Emacs*cursorColor: indianred1
+Emacs*pointerColor: indianred1
+Emacs*menubar*Foreground: Black
+Emacs*menubar*Background: #5f9ea0
+Emacs*popup*Foreground: Black
+Emacs*popup*Background: Gray75
+Emacs*dialog*Foreground: Black
+Emacs*dialog*Background: #A5C0C1
+Emacs*dialog*XmTextField*Background: WhiteSmoke
+Emacs*dialog*XmText*Background: WhiteSmoke
+Emacs*dialog*XmList*Background: WhiteSmoke
+Emacs*scrollBarWidth: 8
+Emacs*Font: -misc-fixed-medium-r-semicondensed--0-0-75-75-c-0-iso8859-1
+Emacs*default.attributeFont: -misc-fixed-medium-r-semicondensed--0-0-75-75-c-0-iso8859-1
+Emacs*italic.attributeFont: -*-courier-medium-o-*-*-*-120-*-*-*-*-iso8859-*
+Emacs*debugger.highlight.attributeBackground: PaleTurquoise
+Emacs*menubar*Font: -*-helvetica-bold-r-*-*-*-120-*-*-*-*-iso8859-*
+Emacs*popup*Font: -*-helvetica-bold-r-*-*-*-120-*-*-*-*-iso8859-*
+Emacs*XmDialogShell*FontList: -*-helvetica-bold-r-*-*-*-120-*-*-*-*-iso8859-*
+Emacs*XmTextField*FontList: -*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*
+Emacs*XmText*FontList: -*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*
+Emacs*XmList*FontList: -*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*
+Emacs*dialog*button1.accelerators: #override\
+<KeyPress>Return: ArmAndActivate()\n\
+<KeyPress>KP_Enter: ArmAndActivate()\n\
+Ctrl<KeyPress>m: ArmAndActivate()\n
+Emacs*XmTextField.translations: #override\n\
+ !<Key>osfBackSpace:   delete-previous-character()\n\
+ !<Key>osfDelete:      delete-previous-character()\n\ !Ctrl<Key>h:
+ delete-previous-character()\n\ !Ctrl<Key>d:           delete-next-character()\n\
+ !Meta<Key>osfDelete:  delete-previous-word()\n\
+ !Meta<Key>osfBackSpace:       delete-previous-word()\n\
+ !Meta<Key>d:          delete-next-word()\n\ !Ctrl<Key>k:              delete-to-end-of-line()\n\
+ !Ctrl<Key>g:          process-cancel()\n\ !Ctrl<Key>b:                backward-character()\n\
+ !<Key>osfLeft:                backward-character()\n\ !Ctrl<Key>f:            forward-character()\n\
+ !<Key>osfRight:               forward-character()\n\ !Meta<Key>b:             backward-word()\n\
+ !Meta<Key>Left:               backward-word()\n\ !Meta<Key>osfLeft:   backward-word()\n\
+ !Meta<Key>f:          forward-word()\n\ |Meta<Key>Right:      forward-word()\n\
+ !Meta<Key>osfRight:   forward-word()\n\ !Ctrl<Key>e:          end-of-line()\n\
+ !Ctrl<Key>a:          beginning-of-line()\n\ !Ctrl<Key>w:             cut-clipboard()\n\
+ !Meta<Key>w:          copy-clipboard()\n\ <Btn2Up>:           copy-primary()\n
+Emacs*dialog*XmPushButton.translations: #override\n\ <Btn1Down>: Arm()\n\
+ <Btn1Down>,<Btn1Up>: Activate()\ Disarm()\n\ <Btn1Down>(2+): MultiArm()\n\
+ <Btn1Up>(2+):       MultiActivate()\n\ <Btn1Up>: Activate()\ Disarm()\n\
+ <Key>osfSelect:       ArmAndActivate()\n\ <Key>osfActivate: ArmAndActivate()\n\
+ <Key>osfHelp: Help()\n\ ~Shift ~Meta ~Alt <Key>Return:        ArmAndActivate()\n\
+ <EnterWindow>:      Enter()\n\ <LeaveWindow>:      Leave()\n
+Mosaic*XmLabel*fontList: -*-helvetica-bold-r-normal-*-14-*-*-*-*-*-iso8859-1
+Mosaic*XmLabelGadget*fontList: -*-helvetica-bold-r-normal-*-14-*-*-*-*-*-iso8859-1
+Mosaic*XmScale*fontList: -*-helvetica-bold-r-normal-*-14-*-*-*-*-*-iso8859-1
+Mosaic*XmBulletinBoard*labelFontList: -*-helvetica-bold-r-normal-*-14-*-*-*-*-*-iso8859-1
+Mosaic*optionmenu.XmLabelGadget*fontList: -*-helvetica-bold-r-normal-*-14-*-*-*-*-*-iso8859-1
+Mosaic*XmPushButton*fontList: -*-helvetica-medium-r-normal-*-14-*-iso8859-1
+Mosaic*XmPushButtonGadget*fontList: -*-helvetica-medium-r-normal-*-14-*-iso8859-1
+Mosaic*XmToggleButton*fontList: -*-helvetica-medium-r-normal-*-14-*-iso8859-1
+Mosaic*XmToggleButtonGadget*fontList: -*-helvetica-medium-r-normal-*-14-*-iso8859-1
+Mosaic*optionmenu*fontList: -*-helvetica-medium-r-normal-*-14-*-iso8859-1
+Mosaic*XmIconGadget*fontList: -*-helvetica-medium-r-normal-*-14-*-iso8859-1
+Mosaic*XmBulletinBoard*buttonFontList: -*-helvetica-medium-r-normal-*-14-*-iso8859-1
+Mosaic*menubar*fontList: -*-helvetica-bold-o-normal-*-14-*-iso8859-1
+Mosaic*XmMenuShell*XmPushButton*fontList: -*-helvetica-bold-o-normal-*-14-*-iso8859-1
+Mosaic*XmMenuShell*XmLabelGadget*fontList: -*-helvetica-bold-o-normal-*-14-*-iso8859-1
+Mosaic*XmMenuShell*XmPushButtonGadget*fontList: -*-helvetica-bold-o-normal-*-14-*-iso8859-1
+Mosaic*XmMenuShell*XmCascadeButton*fontList: -*-helvetica-bold-o-normal-*-14-*-iso8859-1
+Mosaic*XmMenuShell*XmCascadeButtonGadget*fontList: -*-helvetica-bold-o-normal-*-14-*-iso8859-1
+Mosaic*XmCascadeButton*fontList: -*-helvetica-bold-o-normal-*-14-*-iso8859-1
+Mosaic*XmCascadeButtonGadget*fontList: -*-helvetica-bold-o-normal-*-14-*-iso8859-1
+Mosaic*XmMenuShell*XmToggleButton*fontList: -*-helvetica-bold-o-normal-*-14-*-iso8859-1
+Mosaic*XmMenuShell*XmToggleButtonGadget*fontList: -*-helvetica-bold-o-normal-*-14-*-iso8859-1
+Mosaic*pulldownmenu*fontList: -*-helvetica-bold-o-normal-*-14-*-iso8859-1
+Mosaic*XmList*fontList: -*-helvetica-medium-r-normal-*-14-*-iso8859-1
+Mosaic*XmText.fontList: -*-lucidatypewriter-medium-r-normal-*-14-*-iso8859-1
+Mosaic*XmTextField.fontList: -*-lucidatypewriter-medium-r-normal-*-14-*-iso8859-1
+Mosaic*optionmenu*marginHeight: 0
+Mosaic*optionmenu*marginTop: 5
+Mosaic*optionmenu*marginBottom: 5
+Mosaic*optionmenu*marginWidth: 5
+Mosaic*pulldownmenu*XmPushButton*marginHeight: 1
+Mosaic*pulldownmenu*XmPushButton*marginWidth: 1
+Mosaic*pulldownmenu*XmPushButton*marginLeft: 3
+Mosaic*pulldownmenu*XmPushButton*marginRight: 3
+Mosaic*XmList*listMarginWidth: 3
+Mosaic*menubar*marginHeight: 1
+Mosaic*menubar.marginHeight: 0
+Mosaic*menubar*marginLeft: 1
+Mosaic*menubar.spacing: 7
+Mosaic*XmMenuShell*marginLeft: 3
+Mosaic*XmMenuShell*marginRight: 4
+Mosaic*XmMenuShell*XmToggleButtonGadget*spacing: 2
+Mosaic*XmMenuShell*XmToggleButtonGadget*marginHeight: 0
+Mosaic*XmMenuShell*XmToggleButtonGadget*indicatorSize: 12
+Mosaic*XmMenuShell*XmLabelGadget*marginHeight: 4
+Mosaic*XmToggleButtonGadget*spacing: 4
+Mosaic*XmToggleButton*spacing: 4
+Mosaic*XmScrolledWindow*spacing: 0
+Mosaic*XmScrollBar*width: 18
+Mosaic*XmScrollBar*height: 18
+Mosaic*XmScale*scaleHeight: 20
+Mosaic*XmText*marginHeight: 4
+Mosaic*fsb*XmText*width: 420
+Mosaic*fsb*XmTextField*width: 420
+Mosaic*fsb*XmText*height: 500
+Mosaic*fsb*XmTextField*height: 500
+Mosaic*fillOnSelect: True
+Mosaic*visibleWhenOff: True
+Mosaic*XmText*highlightThickness: 0
+Mosaic*XmTextField*highlightThickness: 0
+Mosaic*XmPushButton*highlightThickness: 0
+Mosaic*XmScrollBar*highlightThickness: 0
+Mosaic*highlightThickness: 0
+Mosaic*keyboardFocusPolicy: pointer
+Mosaic*TitleFont: -adobe-times-bold-r-normal-*-24-*-*-*-*-*-iso8859-1
+Mosaic*Font: -adobe-times-medium-r-normal-*-17-*-*-*-*-*-iso8859-1
+Mosaic*ItalicFont: -adobe-times-medium-i-normal-*-17-*-*-*-*-*-iso8859-1
+Mosaic*BoldFont: -adobe-times-bold-r-normal-*-17-*-*-*-*-*-iso8859-1
+Mosaic*FixedFont: -adobe-courier-medium-r-normal-*-17-*-*-*-*-*-iso8859-1
+Mosaic*FixedboldFont: -adobe-courier-bold-r-normal-*-17-*-*-*-*-*-iso8859-1
+Mosaic*FixeditalicFont: -adobe-courier-medium-o-normal-*-17-*-*-*-*-*-iso8859-1
+Mosaic*Header1Font: -adobe-times-bold-r-normal-*-24-*-*-*-*-*-iso8859-1
+Mosaic*Header2Font: -adobe-times-bold-r-normal-*-18-*-*-*-*-*-iso8859-1
+Mosaic*Header3Font: -adobe-times-bold-r-normal-*-17-*-*-*-*-*-iso8859-1
+Mosaic*Header4Font: -adobe-times-bold-r-normal-*-14-*-*-*-*-*-iso8859-1
+Mosaic*Header5Font: -adobe-times-bold-r-normal-*-12-*-*-*-*-*-iso8859-1
+Mosaic*Header6Font: -adobe-times-bold-r-normal-*-10-*-*-*-*-*-iso8859-1
+Mosaic*AddressFont: -adobe-times-medium-i-normal-*-17-*-*-*-*-*-iso8859-1
+Mosaic*PlainFont: -adobe-courier-medium-r-normal-*-14-*-*-*-*-*-iso8859-1
+Mosaic*PlainboldFont: -adobe-courier-bold-r-normal-*-14-*-*-*-*-*-iso8859-1
+Mosaic*PlainitalicFont: -adobe-courier-medium-o-normal-*-14-*-*-*-*-*-iso8859-1
+Mosaic*ListingFont: -adobe-courier-medium-r-normal-*-12-*-*-*-*-*-iso8859-1
+Mosaic*Foreground: #000000000000
+Mosaic*XmScrollBar*Foreground: #afafafafafaf
+Mosaic*Background: #d3d3d3
+Mosaic*XmList*Background: #d3d3d3
+Mosaic*XmText*Background: #d3d3d3
+Mosaic*TroughColor: #545454545454
+Mosaic*XmSelectionBox*Background: #545454545454
+Mosaic*XmMessageBox*Background: #d3d3d3
+Mosaic*XmLabel*Foreground: #1d1d15155b5b
+Mosaic*XmToggleButton*Foreground: #1d1d15155b5b
+Mosaic*XmPushButton*Foreground: #5b5b00000000
+Mosaic*logo*Foreground: #1d1d15155b5b
+Mosaic*XmTextField*Background: #5f9ea0
+Mosaic*SelectColor: #ffffffff0000
+Mosaic*HighlightColor: #afafafafafaf
+Mosaic*TopShadowColor: #efefefefefef
+Mosaic*XmList*TopShadowColor: #efefefefefef
+Mosaic*XmText*TopShadowColor: #efefefefefef
+Mosaic*XmSelectionBox*TopShadowColor: #efefefefefef
+Mosaic*XmMessageBox*TopShadowColor: #efefefefefef
+Mosaic*visitedAnchorColor: #272705055b5b
+Mosaic*anchorColor: #00000000b0b0
+Mosaic*activeAnchorFG: #ffff00000000
+Mosaic*activeAnchorBG: #d3d3d3
+Mosaic*AnchorUnderlines: 1
+Mosaic*VisitedAnchorUnderlines: 1
+Mosaic*DashedVisitedAnchorUnderlines: True
+Mosaic*VerticalScrollOnRight: True
+Mosaic*HomeDocument: http://puff.index.dk/
+Mosaic*ConfirmExit: False
+loopvar: 200
diff --git a/res+log/default.res b/res+log/default.res
new file mode 100644 (file)
index 0000000..64b643c
--- /dev/null
@@ -0,0 +1,13 @@
+# This is default.res
+# $Log: default.res,v $
+# Revision 1.1  1995/02/09 17:27:11  adam
+# Initial revision
+#
+
+a: 1
+b: 2
+long_resource: Makefile adam.res all.log big.res default.res default.res.w
+ gw-log-test* gw-log-test.c gw-log-test.o gw-log.c gw-log.h gw-log.o
+ gw-res-test* gw-res-test.c gw-res-test.o gw-res.c gw-res.c~ gw-res.h
+ gw-res.o gw-resp.h libres+log.a
+# End of file
diff --git a/res+log/gw-log-test.c b/res+log/gw-log-test.c
new file mode 100644 (file)
index 0000000..ea5a226
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+   gw-log-test.c: Test of logging facilities.
+
+   Europagate, 1994-1995.
+
+   $Log: gw-log-test.c,v $
+   Revision 1.1  1995/02/09 17:27:11  adam
+   Initial revision
+
+
+   Initial:       Dec  7, 94 (Adam Dickmeiss)
+   Last update:   Dec 13, 94 (Adam Dickmeiss)
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <gw-log.h>
+
+int main (int argc, char **argv)
+{
+    gw_log_init (*argv);
+
+    gw_log_file (GW_LOG_ALL, "all.log");
+
+    gw_log (GW_LOG_ALL, "Msg", "Hi all, a");
+    gw_log (GW_LOG_STAT, "Msg", "Hi stat, a");
+    gw_log_file (GW_LOG_WARN, "warn.log");
+    gw_log_file (GW_LOG_FATAL, NULL);
+    gw_log (GW_LOG_ALL, "Msg", "Hi all, b");
+    gw_log (GW_LOG_STAT, "Msg", "Hi stat, b");
+    gw_log (GW_LOG_WARN, "Msg", "Hi warn, b");
+    exit (0);
+}
diff --git a/res+log/gw-log.c b/res+log/gw-log.c
new file mode 100644 (file)
index 0000000..bfeccf4
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+   gw-log.c: Implementation of logging facilities.
+
+   Europagate, 1994-1995.
+
+   $Log: gw-log.c,v $
+   Revision 1.1  1995/02/09 17:27:11  adam
+   Initial revision
+
+
+   Initial:       Dec  7, 94 (Adam Dickmeiss)
+   Last update:   Dec 13, 94 (Adam Dickmeiss)
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <gw-log.h>
+
+static char *app_name = NULL;
+static unsigned level = GW_LOG_DEFAULT;
+static int session = 0;
+
+struct file_mask {
+    unsigned mask;           /* level mask for this file entry */
+    int fd;                  /* file descriptor for this file */
+    char *fname;             /* name of file ("" if stdout) */
+    struct file_mask *next;  /* next file in chain */
+};
+
+struct file_mask *file_mask_list = NULL;
+
+char *gw_strdup (const char *s)
+{
+    char *n = malloc (strlen(s)+1);
+    if (n)
+        strcpy (n, s);
+    return n;
+}
+
+void gw_log_init (const char *app_name_a)
+{
+    struct file_mask *list, *list1;
+
+    app_name = gw_strdup (app_name_a);
+    level = GW_LOG_DEFAULT;
+    session = 0;
+
+    /* clean up all output file masks... */
+    for (list = file_mask_list; list; list = list1)
+    {
+        if (list->fd > 2)                  /* avoid closing stdout/stderr */
+            close (list->fd);              
+        free (list->fname);
+        list1 = list->next;
+        free (list);
+    }
+    file_mask_list = NULL;
+}
+
+void gw_log_level (unsigned level_a)
+{
+    level = level_a;
+}
+
+void gw_log_session (int session_a)
+{
+    session = session_a;
+}
+
+int gw_log_file (unsigned level_a, const char *fname_a)
+{
+    struct file_mask **listp, *new_file_mask;
+    listp = &file_mask_list;
+
+    /* go through file mask list and close files already associated */
+    /* on new level */
+    while (*listp)
+    {
+        if (!((*listp)->mask &= ~level_a)) /* any levels left on this one? */
+        {
+            if ((*listp)->fd > 2)          /* close if not stdout/stderr */
+                close ((*listp)->fd);      
+            free ((*listp)->fname);
+            *listp = (*listp)->next;
+        }
+        listp = &(*listp)->next;
+    }
+    if (!fname_a)                          /* stderr? */
+        return 0;                          /* stderr doesn't appear on list */
+    new_file_mask = malloc (sizeof(*new_file_mask));
+    if (!new_file_mask)
+        return -1;
+    new_file_mask->mask = level_a;
+    new_file_mask->next = file_mask_list;
+    file_mask_list = new_file_mask;
+    if (!(file_mask_list->fname = gw_strdup (fname_a)))
+        return -1;
+    if (*fname_a == '\0')                  /* stdout? */
+        new_file_mask->fd = 1;            
+    else                                   /* no, open as usual */
+    {
+        new_file_mask->fd = open (fname_a, O_WRONLY|O_CREAT|O_APPEND, 0666);
+        if (new_file_mask->fd == -1)
+            return -1;
+    }
+    return 0;
+}
+
+int gw_log (unsigned level_a, const char *event_type, const char *format, ...)
+{
+    static char emit_str[2048];
+    struct file_mask *list;
+    va_list ap;
+    unsigned e_level = level_a & level;
+    int count;
+    int err = 0;
+    time_t time_now;
+    char *cp;
+
+    if (!e_level)                          /* any effective level(s)? */      
+        return 0;
+
+    va_start (ap, format);
+    time (&time_now);
+    sprintf (emit_str, "%s %d %s %d %s ", app_name, session,
+             ctime (&time_now), e_level, event_type);
+    if ((cp = strchr (emit_str, '\n')))    /* remove \n from ctime-str */
+        *cp = ' ';
+    count = strlen (emit_str);
+    vsprintf (emit_str+count, format, ap);
+    strcat (emit_str, "\n");
+    count = strlen (emit_str);
+
+    /* go through file mask list... */
+    for (list = file_mask_list; list; list = list->next)
+        if (list->mask & e_level)          /* output this one? */
+        {
+            e_level &= ~list->mask;        /* remove from effective level */
+            if (write (list->fd, emit_str, count) != count)
+                err = 1;
+        }
+    if (e_level)                           /* bits left on effective level? */
+        write (2, emit_str, count);
+    va_end (ap);
+    return err;
+}
diff --git a/res+log/gw-res-test.c b/res+log/gw-res-test.c
new file mode 100644 (file)
index 0000000..ae64b06
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+   gw-res-test.c: Test of resource management.
+
+   Europagate, 1994-1995.
+
+   $Log: gw-res-test.c,v $
+   Revision 1.1  1995/02/09 17:27:11  adam
+   Initial revision
+
+
+   Initial:       Dec  7, 94 (Adam Dickmeiss)
+   Last update:   Dec 13, 94 (Adam Dickmeiss)
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <gw-log.h>
+#include <gw-res.h>
+
+static GwRes res;
+
+static void showf (const char *name, const char *value)
+{
+    printf ("%s: %s\n", name, value);
+}
+
+static void interactive (void)
+{
+    char buffer[128];
+    char arg[3][128];
+    int no_arg;
+    int r;
+
+    while (1)
+    {
+        char *cp;
+        const char *value;
+
+        putc ('>', stdout);
+        fflush (stdout);
+        if (!(fgets (buffer, sizeof(buffer)-1, stdin)))
+            break;
+        while ((cp = strchr (buffer, '\n')))
+            *cp = '\0';
+        if (*buffer == '\0')
+            continue;
+        no_arg = sscanf (buffer+1, "%s %s %s", arg[0], arg[1], arg[2]);
+        r = -10;
+        switch (*buffer)
+        {
+        case 'm':
+            if (no_arg == 1)
+                r = gw_res_merge (res, arg[0]);
+            break;
+        case 'p':
+            if (no_arg == 3)
+                r = gw_res_put (res, arg[0], arg[1], arg[2]);
+            break;
+        case 'g':
+            if (no_arg == 1)
+            {
+                value = gw_res_get (res, arg[0], "<unknown>");
+                printf ("%s has value `%s'\n", arg[0], value);
+                r = 0;
+            }
+            break;
+        case 's':
+            if (no_arg == 1)
+                r = gw_res_trav (res, arg[0], showf);
+            else if (no_arg <= 0)
+                r = gw_res_trav (res, NULL, showf);
+            break;
+        case 'c':
+            if (no_arg == 1)
+                r = gw_res_commit (res, arg[0]);
+            break;
+        case 'h':
+            printf ("m <file>                     merge\n"
+                    "g <name>                     get\n"
+                    "p <name> <value> <file>      put\n"
+                    "s [<file>]                   show\n"
+                    "c <file>                     commit\n"
+                    "q                            quit\n");
+            r = 0;
+            break;
+        case 'q':
+            return;
+        }
+        if (r == -10)
+            printf ("syntax, type 'h' for help\n");
+        else if (r)
+            printf ("returned %d\n", r);
+        else
+            printf ("ok\n");
+    }
+}
+
+static void do_intensive (void)
+{
+    int i;
+    for (i = 0; i<100; i++)
+    {
+        const char *cp;
+        char new_val[12];
+        res = gw_res_init ();
+        
+        gw_res_merge (res, "big.res");
+        gw_res_merge (res, "default.res");
+        gw_res_merge (res, "adam.res");
+
+        cp = gw_res_get (res, "loopvar", "0");
+        sprintf (new_val, "%d", atoi(cp)+1);
+        gw_res_put (res, "loopvar", new_val, "big.res");
+
+        gw_res_commit (res, "big.res");
+        gw_res_close (res);
+    }
+}
+
+int main (int argc, char **argv)
+{
+    gw_log_init (*argv);
+
+    while (--argc > 0)
+    {
+        if (**++argv == '-')
+        {
+            switch (*++*argv)
+            {
+            case 'd':
+                gw_log_level (GW_LOG_ALL);
+                continue;
+            case 't':
+                do_intensive ();
+                return 0;
+            default:
+                gw_log (GW_LOG_FATAL, "Fatal", "Unknown option %s",
+                        *argv);
+                exit (1);
+            }
+        }
+    }
+    gw_log_file (GW_LOG_ALL, "all.log");
+
+    res = gw_res_init ();
+
+    interactive ();
+
+    gw_res_close (res);
+    exit (0);
+}
diff --git a/res+log/gw-res.c b/res+log/gw-res.c
new file mode 100644 (file)
index 0000000..3e43e77
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+   gw-res.c: Implementation of resource management.
+
+   Europagate, 1994-1995.
+
+   $Log: gw-res.c,v $
+   Revision 1.1  1995/02/09 17:27:11  adam
+   Initial revision
+
+
+   Initial:       Dec  8, 94 (Adam Dickmeiss)
+   Last update:   Dec 19, 94 (Adam Dickmeiss)
+
+ */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+
+#if HAVE_FLOCK
+#include <sys/file.h>
+#else
+#include <sys/types.h>
+#endif
+
+#include <gw-log.h>
+#include "gw-resp.h"
+
+/*
+   symtab_open: Create empty symbol table.
+     symbol table handle is returned.
+ */
+
+static struct res_symtab *symtab_open (void)
+{
+    struct res_symtab *symtab;
+
+    symtab = malloc (sizeof(*symtab));
+    if (!symtab)
+        return NULL;
+    symtab->next = NULL;
+    return symtab;
+}
+
+/*
+   symtab_close: Delete symbol table.
+ */
+static void symtab_close (struct res_symtab *symtab)
+{
+    struct res_sym_entry *entry, *entry1;
+
+    for (entry = symtab->next; entry; entry = entry1)
+    {
+        entry1 = entry->next;
+        free (entry);
+    }
+    free (symtab);
+}
+
+/*
+   symtab_override: Add symbol to table. 'rl' holds symbol
+     table entry info. If the symbol is already present it
+     will override old info.
+ */
+static int symtab_override (struct res_symtab *symtab,
+                            struct res_line_info *rl)
+{
+    struct res_sym_entry *entry;
+
+    for (entry = symtab->next; entry; entry=entry->next)
+        if (!strcmp (entry->info->name, rl->name))
+        {
+            entry->info = rl;
+            return 1;
+        }
+    entry = malloc (sizeof(*entry));
+    if (!entry)
+        return -1;
+    entry->next = symtab->next;
+    symtab->next = entry;
+    entry->info = rl;
+    return 0;
+}
+
+/*
+   symtab_lookup: Symbol table lookup. If successful info is returned; 
+     otherwise NULL is returned.
+ */
+static struct res_line_info *symtab_lookup (struct res_symtab *symtab, 
+                                            const char *name)
+{
+    struct res_sym_entry *entry;
+
+    for (entry = symtab->next; entry; entry=entry->next)
+        if (!strcmp (entry->info->name, name))
+            return entry->info;
+    return NULL;
+}
+
+/*
+   lock_file: File locking using fcntl.
+ */
+#if !HAVE_FLOCK
+static void lock_file (int fd, int type)
+{
+    struct flock area;
+    area.l_type = type;
+    area.l_whence = SEEK_SET;
+    area.l_start = 0L;
+    area.l_len = 0L;
+    fcntl (fd, F_SETLKW, &area);
+}
+#endif
+
+/*
+   gw_res_init: A resource handle is returned by this function
+     describing empty resources.
+ */
+GwRes gw_res_init (void)
+{
+    GwRes p;
+
+    if (!(p = malloc (sizeof(*p))))
+        return p;
+    p->files = NULL;
+    p->symtab = symtab_open ();
+    if (!p->symtab)
+    {
+        free (p);
+        return NULL;
+    }
+    return p;
+}
+
+/*
+   gw_res_close: The resources described by 'id' are freed.
+      No further references to 'id' are allowed.
+ */
+void gw_res_close (GwRes id)
+{
+    struct res_line_info *rl, *rl1;
+    struct res_file_info *rf, *rf1;
+    
+    assert (id);
+
+    symtab_close (id->symtab);
+    for (rf = id->files; rf; rf = rf1)
+    {
+        for (rl = rf->lines; rl; rl = rl1)
+        {
+            free (rl->name);
+            free (rl->value);
+            rl1 = rl->next;
+            free (rl);
+        }
+        free (rf->fname);
+        rf1 = rf->next;
+        free (rf);
+    }
+    free (id);
+}
+
+/*
+   add_name: add a node with line information.
+ */
+static struct res_line_info *add_name (enum res_kind kind, 
+                                       const char *name, const char *value)
+{
+    struct res_line_info *rl;
+
+    if (!(rl = malloc (sizeof(*rl))))
+        return NULL;
+    rl->next = NULL;
+    rl->kind = kind;
+    if (name)
+    {
+        rl->name = gw_strdup (name);
+        if (!rl->name)
+        {
+            free (rl);
+            return NULL;
+        }
+    }
+    else
+        rl->name = NULL;
+    if (value)
+    {
+        rl->value = gw_strdup (value);
+        if (!rl->value)
+        {
+            free (rl->name);
+            free (rl);
+            return NULL;
+        }
+    }
+    else
+        rl->value = NULL;
+    return rl;
+}
+
+/*
+   gw_res_merge: The resources described by 'id' are merged by the contents
+     of  'filename'. If a resource is duplicated (in both resources 'id'
+     and the file) the resource is set to the value specified in 'filename'.
+     This function returns 0 on success; -1 on failure ('filename'
+     could not be read)
+ */
+int gw_res_merge (GwRes id, const char *filename)
+{
+    FILE *inf;
+    char buffer[1024];
+    char value[2048];
+    struct res_file_info *ri;
+    struct res_line_info **rlp, *rl;
+    struct res_line_info *rl_last = NULL;
+    int err = 0;
+
+    assert (id);
+    
+    gw_log (GW_LOG_DEBUG, "res", "gw_res_merge");
+    gw_log (GW_LOG_DEBUG, "res", "checking %s", filename);
+    if (!(inf = fopen (filename, "r")))
+        return -1;
+#if HAVE_FLOCK
+    flock (fileno(inf), LOCK_SH);
+#else
+    lock_file (fileno (inf), F_RDLCK);
+#endif
+    if (!(ri = malloc (sizeof (*ri))))
+    {
+        fclose (inf);
+        return -1;
+    }
+    if (!(ri->fname = gw_strdup (filename)))
+    {
+        free (ri);
+        fclose (inf);
+        return -2;
+    }
+    gw_log (GW_LOG_DEBUG, "res", "reading %s", filename);
+    ri->next = id->files;
+    id->files = ri;
+    rlp = &ri->lines;
+    ri->lines = NULL;
+    while (fgets (buffer, sizeof(buffer)-1, inf))
+    {
+        char *cp;
+        while ((cp = strchr (buffer, '\n')))
+            *cp = '\0';
+        if (*buffer == '#')
+        {   /* comment line */
+            rl = add_name (comment, NULL, buffer);
+            if (!rl)
+            {
+                err = -2;
+                break;
+            }
+            *rlp = rl;
+            rlp = &rl->next;
+        }
+        else if (*buffer == '\0' || *buffer == ' ' || *buffer == '\t')
+        {
+            int i = 0;
+            while (buffer[i] == ' ' || buffer[i] == '\t')
+                i++;
+            if (buffer[i] == '\0')
+            {   /* empty line */
+                rl = add_name (blank, NULL, NULL);
+                if (!rl)
+                {
+                    err = -2;
+                    break;
+                }
+                *rlp = rl;
+                rlp = &rl->next;
+            }
+            else
+            {   /* continuation line */
+                int j = strlen (buffer)-1;
+                /* strip trailing blanks */
+                while (buffer[j] == '\t' || buffer[j] == ' ')
+                    --j;
+                buffer[j+1] = '\0';
+                if (rl_last)
+                {
+                    if (strlen(value)+strlen(buffer+i) >= sizeof(value)-2)
+                    {
+                        gw_log (GW_LOG_WARN, "res", "Resource `%s' is "
+                                " truncated", rl_last->name);
+                    }
+                    else
+                    {
+                        /* effectively add one blank, then buffer */
+                        strcat (value, " ");
+                        strcat (value, buffer+i);
+                    }
+                }
+                else
+                    gw_log (GW_LOG_WARN, "res", "Resource file has bad "
+                            "continuation line");
+            }
+        }
+        else 
+        {   /* resource line */
+            int i = 0;
+            if (rl_last)
+            {
+                rl_last->value = gw_strdup (value);
+                rl_last = NULL;
+            }
+            while (buffer[i] && buffer[i] != ':')
+                i++;
+            if (buffer[i] == ':')
+            {
+                int j = strlen(buffer)-1;
+                buffer[i++] = '\0';            /* terminate name */
+                while (buffer[i] == ' ' || buffer[i] == '\t')
+                    i++;                       /* skip blanks before */
+                while (buffer[j] == '\t' || buffer[j] == ' ')
+                    --j;                       /* skip blanks after */
+                buffer[j+1] = '\0';            /* terminate value */
+                strcpy (value, buffer+i);
+                rl_last = add_name (resource, buffer, NULL);
+                if (!rl_last)
+                    err = -2;
+                else
+                {
+                    *rlp = rl_last;
+                    rlp = &rl_last->next;
+                }
+            }
+        }
+    }
+    if (rl_last)
+        rl_last->value = gw_strdup (value);
+#if HAVE_FLOCK
+    flock (fileno (inf), LOCK_UN);
+#else
+    lock_file (fileno (inf), F_UNLCK);
+#endif
+    fclose (inf);
+    gw_log (GW_LOG_DEBUG, "res", "close of %s", filename);
+    for (rl = ri->lines; rl; rl = rl->next)
+    {
+        switch (rl->kind)
+        {
+        case comment:
+            gw_log (GW_LOG_DEBUG, "res", "%s", rl->value);
+            break;
+        case resource:
+            gw_log (GW_LOG_DEBUG, "res", "%s: %s", rl->name, rl->value);
+            if (symtab_override (id->symtab, rl) < 0)
+                err = -2;
+            break;
+        case blank:
+            gw_log (GW_LOG_DEBUG, "res", "");
+            break;
+        default:
+            assert (0);
+        }
+    }
+    gw_log (GW_LOG_DEBUG, "res", "gw_res_merge returned %d", err);
+    return err;
+}
+
+/*
+   gw_res_get: The resource with name 'name' is checked in the resources
+     represented by 'id'. If the resource is present a pointer to the
+     value (null-terminated string) is returned. If the value is not
+     present the value of 'def' is returned.
+ */
+const char *gw_res_get (GwRes id, const char *name, const char *def)
+{
+    struct res_line_info *rl;
+
+    assert (id);
+    rl = symtab_lookup (id->symtab, name);
+    if (!rl)
+        return def;
+    return rl->value;
+}
+
+/*
+   gw_res_put: Change a resource - modify if it exists - add if not
+     already there. The resource will have impact on the file name
+     'fname'. Use gw_res_commit (see below) to actually write to the
+     resource file.
+ */
+int gw_res_put (GwRes id, const char *name, const char *value, 
+                const char *fname)
+{
+    struct res_file_info *ri;
+    struct res_line_info **rlp;
+    assert (id);
+    assert (fname);
+
+    for (ri = id->files; ri; ri = ri->next)
+        if (!strcmp (ri->fname, fname))
+            break;
+    if (!ri)
+    {
+        if (!(ri = malloc (sizeof (*ri))))
+            return -1;
+        if (!(ri->fname = gw_strdup (fname)))
+        {
+            free (ri);
+            return -1;
+        }
+        ri->next = id->files;
+        id->files = ri;
+        ri->lines = NULL;
+    }
+    for (rlp = &ri->lines; *rlp; rlp = &(*rlp)->next)
+        if (!strcmp ((*rlp)->name, name))
+            break;
+    if (*rlp)
+    {
+        char *new_val = gw_strdup (value);
+        if (!new_val)
+            return -1;
+        free ((*rlp)->value);
+        (*rlp)->value = new_val;
+    }
+    else
+    {
+        *rlp = add_name (resource, name, value);
+        if (!*rlp)
+            return -1;
+        (*rlp)->next = NULL;
+        if (symtab_override (id->symtab, *rlp) < 0)
+            return -1;
+    }
+    return 0;
+}
+
+/*
+   gw_res_commit: Write the resource file 'fname'. If resources
+     are modified/added then these will be written now.
+ */
+int gw_res_commit (GwRes id, const char *fname)
+{
+    struct res_file_info *ri;
+    struct res_line_info *rl;
+    FILE *out;
+    int i, pos;
+
+    assert (id);
+    assert (fname);
+
+    for (ri = id->files; ri; ri = ri->next)
+        if (!strcmp (ri->fname, fname))
+            break;
+    if (!ri)
+        return -1;
+    if (!(out = fopen (fname, "w")))
+        return -1;
+#if HAVE_FLOCK
+    flock (fileno (out), LOCK_EX);
+#else
+    lock_file (fileno (out), F_WRLCK);
+#endif
+    for (rl = ri->lines; rl; rl = rl->next)
+        switch (rl->kind)
+        {
+        case comment:
+            fputs (rl->value, out);
+        case blank:
+            fputc ('\n', out);
+            break;
+        case resource:
+            fprintf (out, "%s: ", rl->name);
+            pos = strlen(rl->name)+2;
+            i = 0;
+            while (1)
+            {
+                int left = 78-pos;
+                if (strlen(rl->value+i) <= left)
+                    break;
+                while (left > 0)
+                {
+                    if (rl->value[i+left] == ' ')
+                        break;
+                    
+                    --left;
+                }
+                if (left > 0)
+                {
+                    int j;
+                    for (j = 0; j<left; j++)
+                        fputc (rl->value[i+j], out);
+                    i += left+1;
+                }
+                else
+                    break;
+                fprintf (out, "\n ");
+                pos = 2;
+            }
+            fprintf (out, "%s\n", rl->value+i);
+            break;
+        default:
+            assert (0);
+        }
+    fflush (out);
+#if HAVE_FLOCK
+    flock (fileno (out), LOCK_UN);
+#else
+    lock_file (fileno (out), F_UNLCK);
+#endif
+    fclose (out);
+    return 0;
+}
+
+/*
+   gw_res_trav: Traverse resources associated with file 'fname'. For
+     each resource the handler 'tf' is invoked with name and value.
+ */
+int gw_res_trav (GwRes id, const char *fname, void (*tf)(const char *name,
+                                                         const char *value))
+{
+    assert (id);
+    assert (tf);
+
+    if (fname)
+    {
+        struct res_file_info *ri;
+        struct res_line_info *rl;
+
+        for (ri = id->files; ri; ri = ri->next)
+            if (!strcmp (ri->fname, fname))
+                break;
+        if (!ri)
+            return -1;
+        for (rl = ri->lines; rl; rl = rl->next)
+            if (rl->kind == resource)
+                (*tf) (rl->name, rl->value);
+    }
+    else
+    {
+        struct res_sym_entry *entry;
+        
+        for (entry = id->symtab->next; entry; entry=entry->next)
+            (*tf) (entry->info->name, entry->info->value);
+    }
+    return 0;
+}
+
+
+
diff --git a/res+log/gw-resp.h b/res+log/gw-resp.h
new file mode 100644 (file)
index 0000000..bdd8c8f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+   gw-res.h: Private header file for resource management.
+
+   Europagate, 1994-1995.
+
+   $Log: gw-resp.h,v $
+   Revision 1.1  1995/02/09 17:27:11  adam
+   Initial revision
+
+
+   Initial:       Dec  7, 94 (Adam Dickmeiss)
+   Last update:   Dec 13, 94 (Adam Dickmeiss)
+ */
+
+#include <gw-res.h>
+
+enum res_kind {
+    comment,
+    blank,
+    resource
+};
+
+/* information about each line */
+struct res_line_info {
+    enum res_kind kind;  
+    char *name;
+    char *value;
+    struct res_line_info *next;
+};
+
+/* information about each file */
+struct res_file_info {
+    char *fname;
+    struct res_line_info *lines;
+    struct res_file_info *next;
+};
+
+/* symbol table entry */
+struct res_sym_entry {
+    struct res_line_info *info;
+    struct res_sym_entry *next;
+};
+
+/* symbol table */
+struct res_symtab {
+    struct res_sym_entry *next;
+};
+
+/* all resource information */
+struct Gw_res_info {
+    struct res_file_info *files;
+    struct res_symtab *symtab;
+};
diff --git a/util/Makefile b/util/Makefile
new file mode 100644 (file)
index 0000000..8667026
--- /dev/null
@@ -0,0 +1,49 @@
+# Makefile for Email gateway utilities
+# Europagate, 1995
+#
+# $Log: Makefile,v $
+# Revision 1.1  1995/02/09 17:27:10  adam
+# Initial revision
+#
+SHELL=/bin/sh
+INCLUDE=-I../include
+CFLAGS=-g -Wall -pedantic -ansi
+CC=gcc
+TPROG1=iso2709dump
+LIB=../lib/util.a
+PO=iso2709.o
+CPP=cc -E
+DEFS=$(INCLUDE)
+
+all: $(TPROG1)
+
+$(TPROG1): $(TPROG1).o $(LIB) 
+       $(CC) $(CFLAGS) -o $(TPROG1) $(TPROG1).o $(LIB)
+
+$(LIB): $(PO)
+       rm -f $(LIB)
+       ar qc $(LIB) $(PO)
+       ranlib $(LIB)
+
+.c.o:
+       $(CC) -c $(DEFS) $(CFLAGS) $<
+
+clean:
+       rm -f *.log *.[oa] $(TPROG1) $(TPROG2) core mon.out gmon.out errlist *~
+
+depend: depend2
+
+depend1:
+       mv Makefile Makefile.tmp
+       sed '/^#Depend/q' <Makefile.tmp >Makefile
+       $(CPP) $(INCLUDE) -M *.c >>Makefile
+       -rm Makefile.tmp
+
+depend2:
+       $(CPP) $(INCLUDE) -M *.c >.depend       
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+#Depend --- DOT NOT DELETE THIS LINE
diff --git a/util/iso2709.c b/util/iso2709.c
new file mode 100644 (file)
index 0000000..62cb8fe
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+   gw-res.c: Iso2709 record management
+
+   Europagate, 1994-1995.
+
+   $Log: iso2709.c,v $
+   Revision 1.1  1995/02/09 17:27:10  adam
+   Initial revision
+
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include <iso2709p.h>
+
+static int atoin (const char *buf, int n)
+{
+    int val = 0;
+    while (--n >= 0)
+    {
+        if (isdigit(*buf))
+            val = val*10 + (*buf - '0');
+        buf++;
+    }
+    return val;
+}
+
+static void strncpyx (char *d, const char *s, int n)
+{
+    while (--n >= 0 && *s)
+        if (*s != ISO2709_IDFS)
+            *d++ = *s++;
+        else
+        {
+            *d++ = ' ';
+            s++;
+        }
+    *d = '\0';
+#if 0
+    strncpy (d, s, n);
+    d[n] = '\0';
+#endif
+}
+
+char *iso2709_read (FILE *inf)
+{
+    char length_str[5];
+    int size;
+    char *buf;
+
+    if (fread (length_str, 1, 5, inf) != 5)
+        return NULL;
+    size = atoin (length_str, 5);
+    if (size <= 6)
+        return NULL;
+    if (!(buf = malloc (size+1)))
+        return NULL;
+    if (fread (buf+5, 1, size-5, inf) != (size-5))
+    {
+        free (buf);
+        return NULL;
+    }
+    memcpy (buf, length_str, 5);
+    buf[size] = '\0';
+    return buf;
+}
+
+Iso2709Rec iso2709_cvt (const char *buf)
+{
+    struct iso2709_dir **dpp, *dp;
+    int pos = 24;
+    Iso2709Rec p;
+
+    if (!(p = malloc (sizeof(*p))))
+        return NULL;
+
+    p->record_length = atoin (buf, 5);
+    strncpyx (p->record_status, buf+5, 1);
+    strncpyx (p->implementation_codes, buf+6, 4);
+    p->indicator_length = atoin (buf+10, 1);
+    p->identifier_length = atoin (buf+11, 1);
+    p->base_address = atoin (buf+12, 4);
+    strncpyx (p->user_systems, buf+17, 3);
+
+    p->length_data_entry = atoin (buf+20, 1);
+    p->length_starting = atoin (buf+21, 1);
+    p->length_implementation = atoin (buf+22, 1);
+    strncpyx (p->future_use, buf+23, 1);
+
+    dpp = &p->directory;
+
+    *dpp = NULL;
+    while (buf[pos] != ISO2709_FS)
+    {
+        *dpp = malloc (sizeof(**dpp));
+        (*dpp)->next = NULL;
+        strncpyx ((*dpp)->tag, buf+pos, 3);
+        pos += 3;
+        (*dpp)->length = atoin (buf+pos, p->length_data_entry);
+        pos += p->length_data_entry;
+        (*dpp)->offset = atoin (buf+pos, p->length_starting);
+        pos += p->length_starting + p->length_implementation;
+
+        dpp = &(*dpp)->next;
+    }
+    pos++;
+#if 0
+    fprintf (stderr, "indicator_len=%d, identifier_len=%d\n", 
+             p->indicator_length, p->identifier_length);
+#endif
+    for (dp = p->directory; dp; dp = dp->next)
+    {
+        int tag00;
+        struct iso2709_field **fpp;
+        int dpos = pos+dp->offset;
+        char *save_indicator = NULL;
+
+        fpp = &dp->fields;
+
+        *fpp = malloc (sizeof(**fpp));
+        (*fpp)->next = NULL;
+        if (p->indicator_length && memcmp (dp->tag, "00", 2))
+        {
+            (*fpp)->indicator = malloc (p->indicator_length+1);
+            strncpyx ((*fpp)->indicator, buf+dpos, p->indicator_length);
+            dpos += p->indicator_length;
+        }
+        else
+            (*fpp)->indicator = NULL;
+
+        if (memcmp (dp->tag, "00", 2))
+            tag00 = 0;
+        else
+            tag00 = 1;
+        fprintf (stderr, "%s", dp->tag);
+        while (1)
+        {
+            int dpos_n;
+            if (p->identifier_length && !tag00)
+            {
+                (*fpp)->identifier = malloc (p->identifier_length+1);
+                strncpyx ((*fpp)->identifier, buf+dpos+1,
+                          p->identifier_length-1);
+                dpos += p->identifier_length;
+            }
+            else
+                (*fpp)->identifier = NULL;
+
+            dpos_n = dpos;
+            while (buf[dpos_n] != ISO2709_FS && buf[dpos_n] != ISO2709_IDFS)
+                dpos_n++;
+
+            (*fpp)->data = malloc (dpos_n - dpos + 1);
+            strncpyx ((*fpp)->data, buf+dpos, dpos_n - dpos);
+            dpos = dpos_n;
+            
+            if (!save_indicator && (*fpp)->indicator)
+                fprintf (stderr, " %s", (*fpp)->indicator);
+            if ((*fpp)->identifier)
+                fprintf (stderr, " *%s", (*fpp)->identifier);
+            fprintf (stderr, " %s", (*fpp)->data);
+            if (buf[dpos] == ISO2709_FS)
+                break;
+            
+            save_indicator = (*fpp)->indicator;
+            fpp = &(*fpp)->next;
+            *fpp = malloc (sizeof(**fpp));
+            (*fpp)->next = NULL;
+            (*fpp)->indicator = save_indicator;
+        }
+        fprintf (stderr, "\n");
+    }
+    return p;
+}
diff --git a/util/iso2709dump.c b/util/iso2709dump.c
new file mode 100644 (file)
index 0000000..fbf66dc
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+   gw-res.c: Iso2709 record management
+
+   Europagate, 1994-1995.
+
+   $Log: iso2709dump.c,v $
+   Revision 1.1  1995/02/09 17:27:10  adam
+   Initial revision
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <iso2709.h>
+
+int main (int argc, char **argv)
+{
+    char *buf;
+    Iso2709Rec rec;
+
+    while ((buf = iso2709_read (stdin)))
+    {
+        rec = iso2709_cvt (buf);
+        free (buf);
+    }
+    return 0;
+}