adding zephyr-im master branch

This commit is contained in:
2022-07-25 09:01:27 -06:00
parent 61f5ed8f01
commit ee1236fa5c
311 changed files with 62265 additions and 0 deletions

4
zwgc/.gitattributes vendored Normal file
View File

@ -0,0 +1,4 @@
instantiate ident
zwgc_resources ident
zwgc.desc ident
zwgc.el ident

167
zwgc/Makefile.in Normal file
View File

@ -0,0 +1,167 @@
SHELL=@SHELL@
prefix=@prefix@
exec_prefix=@exec_prefix@
datadir=@datadir@
sysconfdir=@sysconfdir@
sbindir=@sbindir@
lsbindir=@lsbindir@
datarootdir=@datarootdir@
includedir=@includedir@
mandir=@mandir@
libdir=@libdir@
bindir=@bindir@
top_builddir=..
srcdir=@srcdir@
top_srcdir=@top_srcdir@
BUILDTOP=..
VPATH=@srcdir@
LIBTOOL=@LIBTOOL@
CC=@CC@
YACC=@YACC@
INSTALL=@INSTALL@
INSTANTIATE=${srcdir}/instantiate
editman = sed \
-e 's|@datadir[@]|${datadir}|g' \
-e 's|@sysconfdir[@]|${sysconfdir}|g' \
-e 's|@sbindir[@]|${sbindir}|g' \
-e 's|@lsbindir[@]|${lsbindir}|g'
LIBZEPHYR=${BUILDTOP}/lib/libzephyr.la
CPPFLAGS=@CPPFLAGS@
CFLAGS=@CFLAGS@
ALL_CFLAGS=${CFLAGS} -DDATADIR=\"${datadir}\" -I${top_srcdir}/h \
-I${BUILDTOP}/h -I${srcdir} -I. @X_CFLAGS@ ${CPPFLAGS}
YFLAGS=-d
LDFLAGS=@X_LIBS@ @LDFLAGS@
LIBS=${LIBZEPHYR} @LIBS@ -lcom_err @ZWGC_LIBX11@ @X_EXTRA_LIBS@ \
@TLIB@ @REGEX_LIBS@ @ARES_LIBS@
OBJS= port_dictionary.o pointer_dictionary.o unsigned_long_dictionary.o \
string_dictionary.o int_dictionary.o string_dictionary_aux.o \
parser.o lexer.o node.o exec.o buffer.o main.o zephyr.o X_driver.o \
substitute.o port.o xshow.o mux.o eval.o subscriptions.o notice.o \
xcut.o regexp.o character_class.o text_operations.o file.o error.o \
variables.o formatter.o X_fonts.o X_gram.o tty_filter.o \
standard_ports.o xselect.o xmark.o xrevstack.o xerror.o \
new_string.o new_memory.o plus.o
all: zwgc zwgc.1
zwgc: ${OBJS} ${LIBZEPHYR}
${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBS}
port_dictionary.c port_dictionary.h: dictionary.c dictionary.h
${INSTANTIATE} ${srcdir} dictionary port port.h
pointer_dictionary.c pointer_dictionary.h: dictionary.c dictionary.h
${INSTANTIATE} ${srcdir} dictionary pointer pointer.h
unsigned_long_dictionary.c unsigned_long_dictionary.h: dictionary.c \
dictionary.h
${INSTANTIATE} ${srcdir} dictionary unsigned_long unsigned_long.h
string_dictionary.c string_dictionary.h: dictionary.c dictionary.h
${INSTANTIATE} ${srcdir} dictionary string new_string.h
int_dictionary.c int_dictionary.h: dictionary.c dictionary.h
${INSTANTIATE} ${srcdir} dictionary int
char_stack.h: stack.h
${INSTANTIATE} ${srcdir} stack char
string_stack.h: stack.h
${INSTANTIATE} ${srcdir} stack string
xmode_stack.h: stack.h
${INSTANTIATE} ${srcdir} stack xmode
lexer.o: y.tab.h
parser.o: y.tab.c y.tab.h
${CC} -c ${ALL_CFLAGS} -o $@ y.tab.c
y.tab.c y.tab.h: ${srcdir}/parser.y
${YACC} ${YFLAGS} ${srcdir}/parser.y
.c.o:
${CC} -c ${ALL_CFLAGS} $<
zwgc.1: ${srcdir}/zwgc.1.in Makefile
${editman} ${srcdir}/$@.in > $@.tmp
mv $@.tmp $@
check:
install: zwgc zwgc.1
${LIBTOOL} --mode=install ${INSTALL} -m 755 zwgc ${DESTDIR}${bindir}
${INSTALL} -m 644 zwgc.1 ${DESTDIR}${mandir}/man1
${INSTALL} -m 644 ${srcdir}/zwgc.desc ${DESTDIR}${datadir}/zephyr
${INSTALL} -m 644 ${srcdir}/zwgc_resources ${DESTDIR}${datadir}/zephyr
clean:
${LIBTOOL} --mode=clean rm -f zwgc
rm -f ${OBJS} port_dictionary.[ch] pointer_dictionary.[ch]
rm -f unsigned_long_dictionary.[ch] string_dictionary.[ch]
rm -f int_dictionary.[ch] char_stack.h string_stack.h xmode_stack.h
rm -f y.tab.[ch]
rm -f zwgc.1
${OBJS}: ${top_srcdir}/h/sysdep.h ${BUILDTOP}/h/config.h
zephyr.o: ${BUILDTOP}/h/zephyr/zephyr.h ${BUILDTOP}/h/zephyr/zephyr_err.h
port_dictionary.o: port.h string_stack.h new_string.h new_memory.h
pointer_dictionary.o: pointer.h new_string.h new_memory.h
unsigned_long_dictionary.o: new_string.h new_memory.h
string_dictionary.o: new_string.h new_memory.h
int_dictionary.o: new_string.h new_memory.h
X_driver.o: X_driver.h new_memory.h formatter.h mux.h variables.h error.h
X_driver.o: X_gram.h xselect.h unsigned_long_dictionary.h
X_fonts.o: X_fonts.h new_memory.h new_string.h error.h pointer_dictionary.h
X_fonts.o: zwgc.h
X_gram.o: X_gram.h xmark.h zwgc.h X_driver.h X_fonts.h error.h new_string.h
X_gram.o: xrevstack.h xerror.h xselect.h
browser.o: zwgc.h
buffer.o: new_memory.h buffer.h
character_class.o: character_class.h
eval.o: new_memory.h node.h eval.h substitute.h port.h buffer.h regexp.h
eval.o: text_operations.h zwgc.h variables.h
exec.o: new_memory.h exec.h eval.h node.h buffer.h port.h variables.h notice.h
file.o: new_memory.h new_string.h error.h
formatter.o: new_memory.h char_stack.h string_dictionary.h formatter.h
formatter.o: text_operations.h
lexer.o: new_memory.h new_string.h int_dictionary.h lexer.h parser.h
main.o: new_memory.h zwgc.h parser.h node.h exec.h zephyr.h notice.h
main.o: subscriptions.h file.h mux.h port.h variables.h main.h
mux.o: mux.h error.h zwgc.h pointer.h
new_memory.o: new_memory.h int_dictionary.h
new_string.o: new_memory.h
node.o: new_memory.h node.h
notice.o: new_memory.h error.h variables.h notice.h
port.o: new_string.h port_dictionary.h port.h notice.h variables.h
regexp.o: regexp.h
standard_ports.o: new_memory.h port.h variables.h error.h main.h
string_dictionary_aux.o: new_memory.h string_dictionary.h
subscriptions.o: new_memory.h new_string.h int_dictionary.h zwgc.h
subscriptions.o: subscriptions.h error.h file.h main.h
substitute.o: new_memory.h lexer.h substitute.h
text_operations.o: new_memory.h text_operations.h char_stack.h
tty_filter.o: new_memory.h new_string.h string_dictionary_aux.h formatter.h
tty_filter.o: zwgc.h error.h
variables.o: new_memory.h notice.h string_dictionary_aux.h variables.h
xcut.o: new_memory.h new_string.h X_gram.h zwgc.h xselect.h xmark.h error.h
xcut.o: xrevstack.h
xerror.o: mux.h
xmark.o: X_gram.h X_fonts.h xmark.h new_string.h
xrevstack.o: X_gram.h zwgc.h
xselect.o: new_string.h xselect.h
xshow.o: pointer_dictionary.h new_memory.h formatter.h variables.h zwgc.h
xshow.o: X_fonts.h X_gram.h xmode_stack.h
zephyr.o: new_string.h zephyr.h error.h mux.h subscriptions.h variables.h
zephyr.o: pointer.h X_driver.h
.PHONY: all check install clean

412
zwgc/X_driver.c Normal file
View File

@ -0,0 +1,412 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_X_driver_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* The X driver: */
/* */
/****************************************************************************/
#ifndef X_DISPLAY_MISSING
#include <zephyr/zephyr.h>
#include "new_string.h"
#include "X_driver.h"
#include <X11/Xresource.h>
#include "new_memory.h"
#include "formatter.h"
#include "mux.h"
#include "variables.h"
#include "error.h"
#include "X_gram.h"
#include "xselect.h"
#include "unsigned_long_dictionary.h"
#include "zephyr.h"
char *app_instance;
/*
* x_dpy - the display we are outputting to
*/
Display *x_dpy = NULL;
/****************************************************************************/
/* */
/* Code to deal with getting X resources: */
/* */
/****************************************************************************/
/*
*
*/
#ifndef APPNAME
#define APPNAME "zwgc"
#endif
/*
*
*/
#ifndef APPCLASS
#define APPCLASS "Zwgc"
#endif
/*
* x_resources - our X resources from application resources, command line,
* and user's X resources.
*/
static XrmDatabase x_resources = NULL;
/*
* Internal Routine:
*
* int convert_string_to_bool(string text)
* Effects: If text represents yes/true/on, return 1. If text
* representes no/false/off, return 0. Otherwise,
* returns -1.
*/
static int
convert_string_to_bool(string text)
{
if (!strcasecmp("yes", text) || !strcasecmp("y", text) ||
!strcasecmp("true", text) || !strcasecmp("t", text) ||
!strcasecmp("on", text))
return(1);
else if (!strcasecmp("no", text) || !strcasecmp("n", text) ||
!strcasecmp("false", text) || !strcasecmp("f", text) ||
!strcasecmp("off", text))
return(0);
else
return(-1);
}
/*
*
*/
char *
get_string_resource(string name,
string class)
{
string full_name, full_class;
int status;
char *type;
XrmValue value;
full_name = string_Concat(APPNAME, ".");
full_name = string_Concat2(full_name, name);
full_class = string_Concat(APPCLASS, ".");
full_class = string_Concat2(full_class, class);
status = XrmGetResource(x_resources, full_name, full_class, &type, &value);
free(full_name);
free(full_class);
if (status != True)
return(NULL);
if (string_Neq(type, "String"))
return(NULL);
return(value.addr);
}
/*
*
*/
int
get_bool_resource(string name,
string class,
int default_value)
{
int result;
char *temp;
if (!(temp = get_string_resource(name, class)))
return(default_value);
result = convert_string_to_bool(temp);
if (result == -1)
result = default_value;
return(result);
}
static unsigned_long_dictionary color_dict = NULL;
/* Requires: name points to color name or hex string. name must be free'd
* eventually by the caller.
* Effects: returns unsigned long pixel value, or default if the
* color is not known by the server. If name is NULL, returns
* default;
*
* comment: caches return values from X server round trips. If name does
* not resolve, this fact is NOT cached, and will result in a round
* trip each time.
*/
unsigned long
x_string_to_color(char *name,
unsigned long def)
{
unsigned_long_dictionary_binding *binding;
int exists;
XColor xc;
if (name == NULL)
return(def);
binding = unsigned_long_dictionary_Define(color_dict,name,&exists);
if (exists) {
return((unsigned long) binding->value);
} else {
if (XParseColor(x_dpy,
DefaultColormapOfScreen(DefaultScreenOfDisplay(x_dpy)),
name,&xc)) {
if (XAllocColor(x_dpy,
DefaultColormapOfScreen(DefaultScreenOfDisplay(x_dpy)),
&xc)) {
binding->value = (unsigned long) xc.pixel;
return(xc.pixel);
} else {
ERROR2("Error in XAllocColor on \"%s\": using default color\n",
name);
}
} else {
ERROR2("Error in XParseColor on \"%s\": using default color\n",
name);
}
unsigned_long_dictionary_Delete(color_dict,binding);
return(def);
}
/*NOTREACHED*/
}
/*
* Standard X Toolkit command line options:
*/
static XrmOptionDescRec cmd_options[] = {
{"+rv", "*reverseVideo", XrmoptionNoArg, (XPointer) "off"},
{"+synchronous", "*synchronous", XrmoptionNoArg, (XPointer) "off"},
{"-background", "*background", XrmoptionSepArg, (XPointer) NULL},
{"-bd", "*borderColor", XrmoptionSepArg, (XPointer) NULL},
{"-bg", "*background", XrmoptionSepArg, (XPointer) NULL},
{"-bordercolor", "*borderColor", XrmoptionSepArg, (XPointer) NULL},
{"-borderwidth", ".borderWidth", XrmoptionSepArg, (XPointer) NULL},
{"-bw", ".borderWidth", XrmoptionSepArg, (XPointer) NULL},
{"-display", ".display", XrmoptionSepArg, (XPointer) NULL},
{"-fg", "*foreground", XrmoptionSepArg, (XPointer) NULL},
{"-fn", "*font", XrmoptionSepArg, (XPointer) NULL},
{"-font", "*font", XrmoptionSepArg, (XPointer) NULL},
{"-foreground", "*foreground", XrmoptionSepArg, (XPointer) NULL},
{"-geometry", ".geometry", XrmoptionSepArg, (XPointer) NULL},
{"-iconname", ".iconName", XrmoptionSepArg, (XPointer) NULL},
#ifdef CMU_ZWGCPLUS
{"-lifespan", "*lifespan", XrmoptionSepArg, (XPointer) NULL},
#endif
{"-name", ".name", XrmoptionSepArg, (XPointer) NULL},
{"-reverse", "*reverseVideo", XrmoptionNoArg, (XPointer) "on"},
{"-rv", "*reverseVideo", XrmoptionNoArg, (XPointer) "on"},
{"-transient", "*transient", XrmoptionNoArg, (XPointer) "on"},
{"-synchronous", "*synchronous", XrmoptionNoArg, (XPointer) "on"},
{"-title", ".title", XrmoptionSepArg, (XPointer) NULL},
{"-xrm", NULL, XrmoptionResArg, (XPointer) NULL} };
#define NUMBER_OF_OPTIONS ((sizeof (cmd_options))/ sizeof(cmd_options[0]))
/*
*
*/
static int
open_display_and_load_resources(int *pargc,
char **argv)
{
XrmDatabase temp_db1, temp_db2, temp_db3;
char *filename, *res, *xdef;
char dbasename[128];
/* Initialize X resource manager: */
XrmInitialize();
/*
* Parse X toolkit command line arguments (including -display)
* into resources:
*/
XrmParseCommand(&x_resources, cmd_options, NUMBER_OF_OPTIONS, APPNAME,
pargc, argv);
/*
* Try and open the display using the display specified if given.
* If can't open the display, return an error code.
*/
x_dpy = XOpenDisplay(get_string_resource("display", "display"));
if (!x_dpy)
return(1);
/* Read in our application-specific resources: */
sprintf(dbasename, "%s/zephyr/zwgc_resources", DATADIR);
temp_db1 = XrmGetFileDatabase(dbasename);
/*
* Get resources from the just opened display:
*/
xdef = XResourceManagerString(x_dpy);
if (xdef)
temp_db2 = XrmGetStringDatabase(xdef);
else
temp_db2 = NULL;
/*
* Merge the 4 sets of resources together such that when searching
* for resources, they are checking in the following order:
* command arguments, XENVIRONMENT resources, server resources,
* application resources
*/
XrmMergeDatabases(temp_db2, &temp_db1);
#if XlibSpecificationRelease > 4
/* X11 R5 per-screen resources */
res = XScreenResourceString (DefaultScreenOfDisplay (x_dpy));
if (res != NULL)
XrmMergeDatabases(XrmGetStringDatabase(res), &temp_db1);
#endif
/*
* Get XENVIRONMENT resources, if they exist, and merge
*/
filename = getenv("XENVIRONMENT");
if (filename)
{
temp_db3 = XrmGetFileDatabase(filename);
XrmMergeDatabases(temp_db3, &temp_db1);
}
XrmMergeDatabases(x_resources, &temp_db1);
x_resources = temp_db1;
return(0);
}
/*
* X_driver_ioerror: called by Xlib in case of an X IO error.
* Shouldn't return (according to man page).
*
* on IO error, we clean up and exit.
*
* XXX it would be better to set mux_end_loop_p, but we can't return to
* get there (Xlib will exit if this routine returns).
*
*/
static int
X_driver_ioerror(Display *display)
{
ERROR2("X IO error on display '%s'--exiting\n", DisplayString(display));
finalize_zephyr();
exit(1);
return 1;
}
/****************************************************************************/
/* */
/* Code to deal with initializing the driver: */
/* */
/****************************************************************************/
/*ARGSUSED*/
int
X_driver_init(char *drivername,
char notfirst,
int *pargc,
char **argv)
{
string temp;
int is_sync;
/*
* Attempt to open display and read resources, including from the
* command line. If fail, exit with error code, disabling this
* driver:
*/
if (open_display_and_load_resources(pargc, argv)) {
ERROR("Unable to open X display -- disabling X driver.\n");
return(1);
}
XSetIOErrorHandler(X_driver_ioerror);
/*
* For now, set some useful variables using resources:
*/
is_sync = get_bool_resource("synchronous", "Synchronous", 0);
if (is_sync)
XSynchronize(x_dpy, is_sync);
temp = get_string_resource("geometry", "Geometry");
if (temp)
var_set_variable("default_X_geometry", temp);
temp=strrchr(argv[0],'/');
app_instance=string_Copy(temp?temp+1:argv[0]);
color_dict = unsigned_long_dictionary_Create(37);
xshowinit();
x_gram_init(x_dpy);
xicccmInitAtoms(x_dpy);
mux_add_input_source(ConnectionNumber(x_dpy),
(void(*)(void *))x_get_input, x_dpy);
return(0);
}
/****************************************************************************/
/* */
/* The display routine itself: */
/* */
/****************************************************************************/
char *
X_driver(string text)
{
string text_copy;
desctype *desc;
int numstr, numnl;
text_copy = string_Copy(text);
desc = disp_get_cmds(text_copy, &numstr, &numnl);
xshow(x_dpy, desc, numstr, numnl);
free(text_copy);
free_desc(desc);
return(NULL);
}
#endif /* X_DISPLAY_MISSING */

32
zwgc/X_driver.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef x_driver_MODULE
#define x_driver_MODULE
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#include <X11/Xlib.h>
#include "new_string.h"
extern Display *x_dpy;
extern char *X_driver(string);
extern int X_driver_init(char *, char, int *, char **);
extern char *get_string_resource(string, string);
extern int get_bool_resource(string, string, int);
extern unsigned long x_string_to_color(char *, unsigned long);
#endif

255
zwgc/X_fonts.c Normal file
View File

@ -0,0 +1,255 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_X_fonts_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* Code dealing with X fonts: */
/* */
/****************************************************************************/
#ifndef X_DISPLAY_MISSING
#include "X_fonts.h"
#include "new_memory.h"
#include "new_string.h"
#include "error.h"
#include "pointer_dictionary.h"
#include "zwgc.h"
/*
* font_dict - Lookup cache for fonts (the value pointers are XFontSet's)
*/
static pointer_dictionary family_dict = NULL;
static pointer_dictionary fontname_dict = NULL;
static pointer_dictionary fontst_dict = NULL;
/*
* {face,size}_to_string - lookup tables for converting {face,size} int
* constants to ascii strings:
*/
static string face_to_string[] = { "roman", "bold", "italic", "bolditalic" };
static string size_to_string[] = { "small", "medium", "large" };
static char *
get_family(char *style, char *substyle)
{
char *desc;
pointer_dictionary_binding *binding;
int exists;
char *family;
desc=string_Concat("style.", style);
desc=string_Concat2(desc, ".substyle.");
desc=string_Concat2(desc, substyle);
desc=string_Concat2(desc, ".fontfamily");
if (!family_dict)
family_dict = pointer_dictionary_Create(37);
binding = pointer_dictionary_Define(family_dict, desc, &exists);
if (exists) {
free(desc);
return((string) binding->value);
} else {
family = get_string_resource(desc,
"StyleKey.Style1.Style2.Style3.SubstyleKey.Substyle.FontfamilyKey");
free(desc);
if (family == NULL)
pointer_dictionary_Delete(family_dict, binding);
else
binding->value = (pointer)family;
return(family); /* If resource returns NULL, return NULL also */
}
}
static char *
get_specific_fontname(char *family,
int size,
int face)
{
char *desc;
pointer_dictionary_binding *binding;
int exists;
char *fontname;
desc = string_Concat("fontfamily.", family);
desc = string_Concat2(desc, ".");
desc = string_Concat2(desc, size_to_string[size]);
desc = string_Concat2(desc, ".");
desc = string_Concat2(desc, face_to_string[face]);
if (!fontname_dict)
fontname_dict = pointer_dictionary_Create(37);
binding = pointer_dictionary_Define(fontname_dict, desc, &exists);
if (exists) {
free(desc);
return (string)binding->value;
} else {
fontname = get_string_resource(desc, "FontfamilyKey.Fontfamily.Size.Face");
free(desc);
if (fontname == NULL)
pointer_dictionary_Delete(fontname_dict, binding);
else
binding->value = (pointer)fontname;
return fontname; /* If resource returns NULL, return NULL also */
}
}
static XFontSet
get_fontst(Display *dpy, char *fontname)
{
pointer_dictionary_binding *binding;
int exists;
XFontSet fontst;
char **missing_list;
int missing_count;
char *def_string;
if (!fontst_dict)
fontst_dict = pointer_dictionary_Create(37);
binding = pointer_dictionary_Define(fontst_dict, fontname, &exists);
if (exists)
return((XFontSet)binding->value);
fontst = XCreateFontSet(dpy, fontname, &missing_list, &missing_count,
&def_string);
XFreeStringList(missing_list);
if (fontst == NULL)
pointer_dictionary_Delete(fontst_dict,binding);
else
binding->value = (pointer)fontst;
return(fontst); /* If resource returns NULL, return NULL also */
}
static char *
get_fontname(char *family, int size, int face)
{
char *fontname;
fontname = get_specific_fontname(family, size, face);
if (!fontname)
fontname = get_specific_fontname(family, size, ROMAN_FACE);
if (!fontname)
fontname = get_specific_fontname(family, MEDIUM_SIZE, face);
if (!fontname)
fontname = get_specific_fontname(family, MEDIUM_SIZE, ROMAN_FACE);
return(fontname);
}
static XFontSet
complete_get_fontst(Display *dpy,
string style,
string substyle,
int size,
int face)
{
char *family, *fontname;
XFontSet fontst;
family = get_family(style, substyle);
if (!family)
return NULL;
fontname = get_fontname(family, size, face);
if (!fontname)
return NULL;
fontst = get_fontst(dpy, fontname);
if (!fontst)
return NULL;
return fontst;
}
/*
* XFontSet get_font(string style, substyle; int size, face)
* Requires: size is one of SMALL_SIZE, MEDIUM_SIZE, LARGE_SIZE and
* face is one of ROMAN_FACE, BOLD_FACE, ITALIC_FACE,
* BOLDITALIC_FACE.
* Effects: unknown
*/
XFontSet
get_font(Display *dpy,
string style,
string substyle,
int size,
int face)
{
char *family,*fontname;
XFontSet fontst = NULL;
if (size == SPECIAL_SIZE) {
/* attempt to process @font explicitly */
fontst = get_fontst(dpy, substyle);
} else {
family = get_family(style, substyle);
if (family)
fontname = get_fontname(family, size, face);
else
fontname = get_fontname(substyle, size, face);
if (fontname) {
fontst = get_fontst(dpy, fontname);
if (fontst)
return fontst;
}
/* At this point, the no-failure case didn't happen, and the case
of substyle being the fontfamily didn't happen, either. */
fontst = complete_get_fontst(dpy, style, "text", size, face);
if (!fontst)
fontst = complete_get_fontst(dpy, "default", substyle, size, face);
if (!fontst)
fontst = complete_get_fontst(dpy, "default", "text", size, face);
if (!fontst) {
fontname = get_fontname("default", size, face);
if (fontname)
fontst = get_fontst(dpy, fontname);
}
}
if (fontst)
return fontst;
/* If all else fails, try fixed */
fontst = get_fontst(dpy, "fixed");
if (fontst)
return fontst;
/* No fonts available. Die. */
ERROR("Unable to open font \"fixed\". Aborting...");
#ifdef DEBUG
abort();
#else
exit(1);
#endif
}
#endif /* X_DISPLAY_MISSING */

46
zwgc/X_fonts.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef x_fonts_MODULE
#define x_fonts_MODULE
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#include "X_driver.h"
#define SPECIAL_FACE -1
#define ROMAN_FACE 0
#define BOLD_FACE 1
#define ITALIC_FACE 2
#define BOLD_ITALIC_FACE 3
#define SPECIAL_SIZE -1
#define SMALL_SIZE 0
#define MEDIUM_SIZE 1
#define LARGE_SIZE 2
/*
* XFontSet get_font(string family; int size, face)
* Requires: size is one of SMALL_SIZE, MEDIUM_SIZE, LARGE_SIZE and
* face is one of ROMAN_FACE, BOLD_FACE, ITALIC_FACE,
* BOLDITALIC_FACE.
* Effects: Looks up the font specified by the above in the
* X resources. If that font is not specified by in
* the X resources or it can't be loaded, the font
* specified by default.medium.roman is used. <<<>>>
*/
extern XFontSet get_font(Display *, string, string, int, int);
#endif

562
zwgc/X_gram.c Normal file
View File

@ -0,0 +1,562 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_X_gram_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
#ifndef X_DISPLAY_MISSING
#include <zephyr/zephyr.h>
#include "X_gram.h"
#include "xmark.h"
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/Xatom.h>
#include "zwgc.h"
#include "X_driver.h"
#include "X_fonts.h"
#include "error.h"
#include "new_string.h"
#include "xrevstack.h"
#include "xerror.h"
#include "xselect.h"
#ifdef CMU_ZWGCPLUS
#include "plus.h"
#endif
extern XContext desc_context;
extern char *app_instance;
/*
*
*/
int internal_border_width = 2;
unsigned long default_fgcolor;
unsigned long default_bgcolor;
unsigned long default_bordercolor;
long ttl = 0;
static int reset_saver;
static int border_width = 1;
static int cursor_code = XC_sailboat;
static int set_transient;
static int enable_delete;
static char *title_name,*icon_name;
static Cursor cursor;
static Window group_leader; /* In order to have transient windows,
* I need a top-level window to always exist
*/
static XClassHint classhint;
static XSetWindowAttributes xattributes;
static unsigned long xattributes_mask;
static int set_all_desktops = True;
static Atom net_wm_desktop = None;
static Atom net_wm_window_type = None;
static Atom net_wm_window_type_utility = None;
/* ICCCM note:
*
* the following properties must be set on all top-level windows:
*
* WM_NAME XStoreName(dpy,w,name);
* WM_ICON_NAME XSetIconName(dpy,w,name);
* WM_NORMAL_HINTS XSetNormalHints(dpy,w,sizehints);
* WM_HINTS XSetWMHints(dpy,w,wmhints);
* WM_CLASS XSetClassHint(dpy,w,classhint);
*
* and for individual zgrams:
*
* WM_TRANSIENT_FOR XSetTransientForHint(dpy,w,main_window);
* WM_PROTOCOLS XSetWMProtocols(dpy,w,protocols,cnt);
*/
/* set all properties defined in ICCCM. If main_window == 0,
* per-zgram initialization is not done.
*/
/*ARGSUSED*/
static void
x_set_icccm_hints(Display *dpy,
Window w,
char *name,
char *wm_icon_name,
XSizeHints *psizehints,
XWMHints *pwmhints,
Window main_window)
{
XStoreName(dpy,w,name);
XSetIconName(dpy,w,wm_icon_name);
XSetWMNormalHints(dpy,w,psizehints);
XSetWMHints(dpy,w,pwmhints);
XSetClassHint(dpy,w,&classhint);
/* in order for some wm's to iconify, the window shouldn't be transient.
e.g. Motif wm */
if (main_window != None) {
if (set_transient)
XSetTransientForHint(dpy,w,main_window);
}
if (enable_delete)
XSetWMProtocols(dpy,w,&XA_WM_DELETE_WINDOW,1);
}
void
x_gram_init(Display *dpy)
{
char *temp;
XSizeHints sizehints;
XWMHints wmhints;
unsigned long rv,tc;
default_fgcolor = BlackPixelOfScreen(DefaultScreenOfDisplay(dpy));
default_bgcolor = WhitePixelOfScreen(DefaultScreenOfDisplay(dpy));
rv = get_bool_resource("reverseVideo", "ReverseVideo", 0);
if (rv) {
tc = default_fgcolor;
default_fgcolor = default_bgcolor;
default_bgcolor = tc;
}
temp = get_string_resource("foreground", "Foreground");
if (temp)
default_fgcolor = x_string_to_color(temp, default_fgcolor);
temp = get_string_resource("background", "Background");
if (temp)
default_bgcolor = x_string_to_color(temp, default_bgcolor);
default_bordercolor = default_fgcolor;
temp = get_string_resource("borderColor", "BorderColor");
if (temp)
default_bordercolor = x_string_to_color(temp, default_bordercolor);
temp = get_string_resource("minTimeToLive", "MinTimeToLive");
if (temp && atoi(temp)>=0)
ttl = atoi(temp);
#ifdef CMU_ZWGCPLUS
if (ttl == 0) {
temp = get_string_resource("lifespan", "LifeSpan");
if (temp && atoi(temp)>=0)
ttl = atoi(temp);
}
get_full_names = get_bool_resource("getFullNames", "GetFullNames", 0);
#endif
reverse_stack = get_bool_resource("reverseStack", "ReverseStack", 0);
reset_saver = get_bool_resource("resetSaver", "ResetSaver", 1);
/* The default here should be 1, but mwm sucks */
set_transient = get_bool_resource("transient", "Transient", 0);
enable_delete = get_bool_resource("enableDelete", "EnableDelete", 1);
temp = get_string_resource("borderWidth", "BorderWidth");
/* <<<>>> */
if (temp && atoi(temp)>=0)
border_width = atoi(temp);
temp = get_string_resource("internalBorder", "InternalBorder");
/* <<<>>> */
if (temp && atoi(temp)>=0)
internal_border_width = atoi(temp);
temp = get_string_resource("cursorCode", "CursorCode");
/* <<<>>> */
if (temp && atoi(temp))
cursor_code = atoi(temp);
cursor = XCreateFontCursor(dpy, cursor_code);
if (!cursor)
cursor = XCreateFontCursor(dpy, XC_sailboat);
temp = get_string_resource("pointerColor", "Foreground");
if (temp) {
char *temp2;
XColor cursor_fore, cursor_back;
/* XXX need to do our own parsing here, since the RecolorCursor
routine requires an XColor, not an unsigned long (pixel) */
if (!(temp2 = get_string_resource("background","Background"))) {
if (default_bgcolor == WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)))
temp2 = "white";
else
temp2 = "black";
}
if (XParseColor(dpy,
DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy)),
temp, &cursor_fore) &&
XParseColor(dpy,
DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy)),
temp2, &cursor_back)) {
XRecolorCursor(dpy, cursor, &cursor_fore, &cursor_back);
}
}
if (!(title_name=get_string_resource("title","Title")))
if (!(title_name=get_string_resource("name","Name")))
title_name=app_instance;
if (!(icon_name=get_string_resource("iconName","IconName")))
if (!(icon_name=get_string_resource("name","Name")))
icon_name=app_instance;
if (!(temp=get_string_resource("name","Name")))
if (!(temp=(char *) getenv("RESOURCE_NAME")))
temp=app_instance;
classhint.res_name=string_Copy(temp);
classhint.res_class="Zwgc";
if (set_transient) {
group_leader=XCreateSimpleWindow(dpy,DefaultRootWindow(dpy),0,0,100,100,
0,default_bordercolor,default_bgcolor);
sizehints.x = 0;
sizehints.y = 0;
sizehints.width = 100;
sizehints.height = 100;
sizehints.flags = PPosition | PSize;
wmhints.input = False;
wmhints.initial_state = DontCareState;
wmhints.flags = InputHint | StateHint;
x_set_icccm_hints(dpy,group_leader,"ZwgcGroup","ZwgcGroup",&sizehints,
&wmhints,0);
}
xattributes.border_pixel = default_bordercolor;
xattributes.cursor = cursor;
xattributes.event_mask = (ExposureMask|ButtonReleaseMask|ButtonPressMask
|LeaveWindowMask|Button1MotionMask
#ifdef CMU_ZWGCPLUS
|KeyPressMask
#endif
|Button3MotionMask|StructureNotifyMask);
xattributes_mask = (CWBackPixel|CWBorderPixel|CWEventMask|CWCursor);
set_all_desktops = get_bool_resource("allDesktops", "AllDesktops", True);
net_wm_desktop = XInternAtom(dpy, "_NET_WM_DESKTOP", False);
net_wm_window_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
net_wm_window_type_utility = XInternAtom(dpy,
"_NET_WM_WINDOW_TYPE_UTILITY",
False);
temp = get_string_resource ("backingStore", "BackingStore");
if (!temp)
return;
xattributes_mask |= CWBackingStore;
if (!strcasecmp (temp, "notuseful"))
xattributes.backing_store = NotUseful;
else if (!strcasecmp (temp, "whenmapped"))
xattributes.backing_store = WhenMapped;
else if (!strcasecmp (temp, "always"))
xattributes.backing_store = Always;
else if (!strcasecmp (temp, "default"))
xattributes_mask &= ~CWBackingStore;
else {
switch (get_bool_resource ("backingStore", "BackingStore", -1)) {
case 0:
xattributes.backing_store = NotUseful;
break;
case 1:
xattributes.backing_store = WhenMapped;
break;
case -1:
fprintf (stderr,
"zwgc: Cannot interpret backing-store resource value `%s'.\n",
temp);
xattributes_mask &= ~CWBackingStore;
break;
}
}
}
static int
x_calc_gravity(int xalign,
int yalign)
{
if (yalign > 0) { /* North */
return (xalign > 0) ? NorthWestGravity
: (xalign == 0) ? NorthGravity
: NorthEastGravity;
} else if (yalign == 0) { /* Center */
return (xalign > 0) ? WestGravity
: (xalign == 0) ? CenterGravity
: EastGravity;
} else { /* South */
return (xalign > 0) ? SouthWestGravity
: (xalign == 0) ? SouthGravity
: SouthEastGravity;
}
}
void
x_gram_create(Display *dpy,
x_gram *gram,
int xalign,
int yalign,
int xpos,
int ypos,
int xsize,
int ysize,
int beepcount)
{
Window w;
XSizeHints sizehints;
XWMHints wmhints;
XSetWindowAttributes attributes;
unsigned long all_desktops = 0xFFFFFFFF;
/*
* Adjust xpos, ypos based on the alignments xalign, yalign and the sizes:
*/
if (xalign < 0)
xpos = WidthOfScreen(DefaultScreenOfDisplay(dpy))
- xpos - xsize - 2 * border_width;
else if (xalign == 0)
xpos = ((WidthOfScreen(DefaultScreenOfDisplay(dpy))
- xsize - 2 * border_width) >> 1) + xpos;
if (yalign<0)
ypos = HeightOfScreen(DefaultScreenOfDisplay(dpy))
- ypos - ysize - 2 * border_width;
else if (yalign == 0)
ypos = ((HeightOfScreen(DefaultScreenOfDisplay(dpy))
- ysize - 2 * border_width) >> 1) + ypos;
/*
* Create the window:
*/
attributes = xattributes;
attributes.background_pixel = gram->bgcolor;
gram->w = w = XCreateWindow (dpy, DefaultRootWindow (dpy), xpos, ypos,
xsize, ysize, border_width, 0,
CopyFromParent, CopyFromParent,
xattributes_mask, &attributes);
sizehints.x = xpos;
sizehints.y = ypos;
sizehints.width = xsize;
sizehints.height = ysize;
sizehints.win_gravity = x_calc_gravity(xalign, yalign);
sizehints.flags = USPosition | USSize | PWinGravity;
wmhints.input = False;
wmhints.initial_state = NormalState;
if (set_transient) {
wmhints.window_group = group_leader;
wmhints.flags = InputHint | StateHint | WindowGroupHint;
x_set_icccm_hints(dpy, w, title_name, icon_name, &sizehints, &wmhints,
group_leader);
} else {
wmhints.flags = InputHint | StateHint;
x_set_icccm_hints(dpy, w, title_name, icon_name, &sizehints, &wmhints, 0);
}
if (net_wm_window_type != None && net_wm_window_type_utility != None)
XChangeProperty(dpy, w, net_wm_window_type, XA_ATOM, 32, PropModeReplace,
(unsigned char *) &net_wm_window_type_utility, 1);
if (set_all_desktops && net_wm_desktop != None)
XChangeProperty(dpy, w, net_wm_desktop, XA_CARDINAL, 32, PropModeReplace,
(unsigned char *) &all_desktops, 1);
XSaveContext(dpy, w, desc_context, (XPointer)gram);
gram->can_die.tv_sec = 0;
XMapWindow(dpy, w);
if (beepcount)
XBell(dpy, 0);
xerror_happened = 0;
if (reverse_stack && bottom_gram) {
XWindowChanges winchanges;
winchanges.sibling = bottom_gram->w;
winchanges.stack_mode = Below;
/* Metacity may use border_width even if it's not specified in
* the value mask, so we must initialize it. See:
* http://bugzilla.gnome.org/show_bug.cgi?id=305257 */
winchanges.border_width = border_width;
begin_xerror_trap (dpy);
XReconfigureWMWindow (dpy, w, DefaultScreen (dpy),
CWSibling | CWStackMode, &winchanges);
end_xerror_trap (dpy);
if (xerror_happened) {
/* The event didn't go. Print an error message, and continue. */
ERROR ("Error configuring window to the bottom of the stack.\n");
}
}
/* we always need to keep a linked list of windows */
add_to_bottom(gram);
if (xerror_happened)
pull_to_top(gram);
if (reset_saver)
XResetScreenSaver(dpy);
XFlush(dpy);
/* Because the flushing/syncing/etc with the error trapping can cause
events to be read into the Xlib queue, we need to go through the queue
here before exiting so that any pending events get processed.
*/
x_get_input(dpy);
}
inline static void
SetFG(Display *dpy, GC gc, unsigned long foreground) {
XGCValues gcvals;
gcvals.foreground = foreground;
XChangeGC(dpy, gc, GCForeground, &gcvals);
}
static void
x_gram_draw(Display *dpy, Window w, x_gram *gram, Region region)
{
int i;
GC gc;
XGCValues gcvals;
xblock *xb;
#ifdef X_HAVE_UTF8_STRING
XmbTextItem text;
#else
XwcTextItem text;
#endif
int startblock, endblock, startpixel = 0, endpixel = 0;
gc = XCreateGC(dpy, w, 0, &gcvals);
XSetRegion(dpy, gc, region);
if ((markgram == gram) && (STARTBLOCK != -1) && (ENDBLOCK != -1)) {
if (xmarkSecond() == XMARK_END_BOUND) {
startblock = STARTBLOCK;
endblock = ENDBLOCK;
startpixel = STARTPIXEL;
endpixel = ENDPIXEL;
} else {
startblock = ENDBLOCK;
endblock = STARTBLOCK;
startpixel = ENDPIXEL;
endpixel = STARTPIXEL;
}
} else {
startblock = -1;
endblock = -1;
}
for (i=0, xb = gram->blocks; i < gram->numblocks; i++, xb++) {
if (XRectInRegion(region, xb->x1, xb->y1, xb->x2 - xb->x1,
xb->y2 - xb->y1) != RectangleOut) {
if (i == startblock) {
if (i == endblock) {
SetFG(dpy, gc, gram->bgcolor);
XFillRectangle(dpy, w, gc, xb->x1, xb->y1, startpixel,
xb->y2 - xb->y1);
SetFG(dpy, gc, xb->fgcolor);
XFillRectangle(dpy, w, gc, xb->x1 + startpixel, xb->y1,
endpixel - startpixel, xb->y2 - xb->y1);
SetFG(dpy, gc, gram->bgcolor);
XFillRectangle(dpy, w, gc, xb->x1 + endpixel, xb->y1,
xb->x2 - xb->x1 - endpixel, xb->y2 - xb->y1);
} else {
SetFG(dpy, gc, gram->bgcolor);
XFillRectangle(dpy, w, gc, xb->x1, xb->y1, startpixel,
xb->y2 - xb->y1);
SetFG(dpy, gc, xb->fgcolor);
XFillRectangle(dpy, w, gc, xb->x1 + startpixel, xb->y1,
xb->x2 - xb->x1 - startpixel,xb->y2 - xb->y1);
}
} else if (i == endblock) {
SetFG(dpy, gc, xb->fgcolor);
XFillRectangle(dpy, w, gc, xb->x1, xb->y1, endpixel,
xb->y2 - xb->y1);
SetFG(dpy, gc, gram->bgcolor);
XFillRectangle(dpy, w, gc, xb->x1 + endpixel, xb->y1,
xb->x2 - xb->x1 - endpixel, xb->y2 - xb->y1);
} else {
if (startblock < i && i < endblock) {
SetFG(dpy, gc, xb->fgcolor);
} else {
SetFG(dpy, gc, gram->bgcolor);
}
XFillRectangle(dpy, w, gc, xb->x1, xb->y1, xb->x2 - xb->x1,
xb->y2 - xb->y1);
}
}
}
gcvals.function = GXxor;
XChangeGC(dpy, gc, GCFunction, &gcvals);
for (i=0, xb = gram->blocks; i < gram->numblocks; i++, xb++) {
if (XRectInRegion(region, xb->x1, xb->y1, xb->x2 - xb->x1,
xb->y2 - xb->y1) != RectangleOut) {
SetFG(dpy, gc, gram->bgcolor ^ xb->fgcolor);
#ifdef X_HAVE_UTF8_STRING
text.chars = xb->wstr;
#else
text.chars = (wchar_t *)xb->wstr;
#endif
text.nchars = xb->wlen;
text.delta = 0;
text.font_set = xb->font;
#ifdef X_HAVE_UTF8_STRING
Xutf8DrawText(dpy, w, gc, xb->x, xb->y, &text, 1);
#else
XwcDrawText(dpy, w, gc, xb->x, xb->y, &text, 1);
#endif
}
}
XFreeGC(dpy, gc);
}
void
x_gram_expose(Display *dpy,
Window w,
x_gram *gram,
XExposeEvent *event)
{
static Region region;
static int partregion;
XRectangle rect;
rect.x = (short) event->x;
rect.y = (short) event->y;
rect.width = (unsigned short) event->width;
rect.height = (unsigned short) event->height;
#ifdef MARK_DEBUG
printf("----- xeventExpose:\nx=%d y=%d w=%d h=%d\n-----",
event->x,event->y,event->width,event->height);
#endif
if (! partregion) {
region=XCreateRegion();
partregion = 1;
}
if (rect.width && rect.height) XUnionRectWithRegion(&rect,region,region);
if (event->count == 0) {
x_gram_draw(dpy,w,gram,region);
partregion = 0;
XDestroyRegion(region);
}
}
#endif /* X_DISPLAY_MISSING */

92
zwgc/X_gram.h Normal file
View File

@ -0,0 +1,92 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef x_gram_TYPE
#define x_gram_TYPE
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <sys/time.h>
#include "formatter.h"
typedef struct _xblock {
unsigned long fgcolor;
XFontSet font;
int x,y;
int x1,y1,x2,y2; /* bounds of block. used for cut and paste. */
int strindex;
int strlen;
char *wstr;
int wlen;
} xblock;
typedef struct _x_gram {
unsigned long bgcolor;
int numblocks;
xblock *blocks;
char *text;
struct _x_gram *below,*above;
Window w;
#ifdef CMU_ZWGCPLUS
ZNotice_t *notice;
#endif
struct timeval can_die;
} x_gram;
typedef struct _xauxblock {
int align;
XFontSet font;
char *str;
int len;
int width;
} xauxblock;
typedef struct _xmode {
int bold;
int italic;
int size;
int align;
int expcolor;
unsigned long color;
char *substyle;
char *font;
} xmode;
typedef struct _xlinedesc {
int startblock;
int numblock;
int lsize;
int csize;
int rsize;
int ascent;
int descent;
} xlinedesc;
/* alignment values: */
#define LEFTALIGN 0
#define CENTERALIGN 1
#define RIGHTALIGN 2
extern void x_gram_init(Display *);
extern void x_gram_create(Display *, x_gram *, int, int, int, int, int, int, int);
extern void x_gram_expose(Display *, Window, x_gram *, XExposeEvent *);
extern void xshow(Display *, desctype *, int, int);
extern void xcut(Display *, XEvent *, XContext);
extern void x_get_input(Display *);
extern void xshowinit(void);
#endif

55
zwgc/browser.c Normal file
View File

@ -0,0 +1,55 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#if (!defined(lint) && !defined(SABER))
static char rcsid_browser_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
#include <sysdep.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "zwgc.h"
static int browser_fd;
struct sockaddr_un sun;
int BOpenSocket()
{
int fd,len;
char *temp;
if ((fd=socket(PF_UNIX,SOCK_STREAM,0)) == -1)
return(-1);
sun.sun_family=AF_UNIX;
if (temp=getenv("WGSOCK"))
strncpy(sun.sunpath,temp,sizeof(sun.sunpath));
else
sprintf(sun.sun_path,"/tmp/.zwgc.%d",getuid());
if (bind(fd,(struct sockaddr *) &sun,
(len=strlen(sun.sunpath)) > sizeof(sun.sunpath)?
sizeof(sun.sunpath):len) == -1) {
close(fd);
return(-1);
}
if (listen(fd,5) == -1) {
unlink(sun.sunpath);
close(fd);
return(-1);
}
return(fd);
}

40
zwgc/browser.h Normal file
View File

@ -0,0 +1,40 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#define BROWSER_NEW_REQ 1
#define BROWSER_NEW_REQ_RESP 2
#define BROWSER_ZPACKET 3
#define BROWSER_ZPACKET_RESP 4
#define BROWSER_TEXT 5
#define BROWSER_WINDOW_ID 6
#define BROWSER_VAR_REQ 7
#define BROWSER_VAR_REQ_RESP 8
#define BROWSER_TYPE_OVERRIDE 11
#define BROWSER_TYPE_DRIVER 12
#define BROWSER_TYPE_WM 13
#define BROWSER_TYPE_SIMPLE 14
#define BROWSER_ACK 21
#define BROWSER_NAK 22
#define BROWSER_KEEP 31
#define BROWSER_LOSE 32
extern int ZBOpenConnection();
extern void ZBCloseConnection( /* int fd */ );
extern char *var_get_variable( /* char *varname */ );

46
zwgc/buffer.c Normal file
View File

@ -0,0 +1,46 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_buffer_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
#include "new_memory.h"
#include "buffer.h"
static char *buffer = 0;
string
buffer_to_string(void)
{
return(buffer);
}
void
clear_buffer(void)
{
if (buffer)
free(buffer);
buffer = string_Copy("");
}
void
append_buffer(char *str)
{
buffer = string_Concat2(buffer, str);
}

26
zwgc/buffer.h Normal file
View File

@ -0,0 +1,26 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef buffer_MODULE
#define buffer_MODULE
#include "new_string.h"
extern string buffer_to_string(void);
extern void clear_buffer(void);
extern void append_buffer(char *);
#endif

45
zwgc/character_class.c Normal file
View File

@ -0,0 +1,45 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_character_class_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
#include <zephyr/zephyr.h>
#include "character_class.h"
/*
* It may look like we are passing the cache by value, but since it's
* really an array we are passing by reference. C strikes again....
*/
static character_class cache;
/* character_class */
char *
string_to_character_class(string str)
{
int i, l;
(void) memset(cache, 0, sizeof(cache));
l = strlen(str);
for (i = 0; i < l; i++)
cache[(unsigned char)str[i]] = 1;
return(cache);
}

28
zwgc/character_class.h Normal file
View File

@ -0,0 +1,28 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef character_class_TYPE
#define character_class_TYPE
#include "new_string.h"
#define NUMBER_OF_CHARACTERS 256
typedef char character_class[NUMBER_OF_CHARACTERS];
extern /* character_class */ char * string_to_character_class(string);
#endif

260
zwgc/dictionary.c Normal file
View File

@ -0,0 +1,260 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_dictionary_c[] = "$Id$";
#endif
/*
* dictionary - a module implementing a generic dictionary. That is,
* any type can be used for the values that keys are bound to.
* Keys are always strings.
*
* Overview:
*
* A dictionary is a set of bindings which bind values of some
* type (this type is the generic parameter of the dictionary) to
* strings. At most one value can be bound to any one string.
* The value that a string is bound to can be changed later.
* Bindings can also be deleted later. It is also possible to
* enumerate all of the bindings in a dictionary. Dictionarys
* are heap based and must be created & destroyed accordingly.
*
* Note: This module assumes that malloc NEVER returns 0 for reasonable
* requests. It is the users responsibility to either ensure that
* this happens or supply a version of malloc with error
* handling.
*
* Dictionarys are mutable.
*
* Implementation:
*
* A standard chaining hash table is used to implement dictionarys.
* Each dictionary has an associated size (# of slots), allowing
* different size dictionaries as needed.
*/
#include "TYPE_T_dictionary.h"
#include "new_string.h"
#include "new_memory.h"
#ifndef NULL
#define NULL 0
#endif
/*
* TYPE_T_dictionary TYPE_T_dictionary_Create(int size):
* Requires: size > 0
* Effects: Returns a new empty dictionary containing no bindings.
* The returned dictionary must be destroyed using
* TYPE_T_dictionary_Destroy. Size is a time vs space
* parameter. For this implementation, space used is
* proportional to size and time used is proportional
* to number of bindings divided by size. It is preferable
* that size is a prime number.
*/
TYPE_T_dictionary
TYPE_T_dictionary_Create(int size)
{
int i;
TYPE_T_dictionary result;
result = (TYPE_T_dictionary)malloc(sizeof(struct _TYPE_T_dictionary));
result->size = size;
result->slots = (TYPE_T_dictionary_binding **)malloc(
size*sizeof(TYPE_T_dictionary_binding *));
for (i=0; i<size; i++)
result->slots[i] = NULL;
return(result);
}
/*
* void TYPE_T_dictionary_Destroy(TYPE_T_dictionary d):
* Requires: d is a non-destroyed TYPE_T_dictionary
* Modifies: d
* Effects: Destroys dictionary d freeing up the space it consumes.
* Dictionary d should never be referenced again. Note that
* free is NOT called on the values of the bindings. If
* this is needed, the client must do this first using
* TYPE_T_dictionary_Enumerate.
*/
void
TYPE_T_dictionary_Destroy(TYPE_T_dictionary d)
{
int i;
TYPE_T_dictionary_binding *binding_ptr, *new_binding_ptr;
for (i=0; i<d->size; i++) {
binding_ptr = d->slots[i];
while (binding_ptr) {
new_binding_ptr = binding_ptr->next;
free(binding_ptr->key);
free(binding_ptr);
binding_ptr = new_binding_ptr;
}
}
free(d->slots);
free(d);
}
/*
* void TYPE_T_dictionary_Enumerate(TYPE_T_dictionary d; void (*proc)()):
* Requires: proc is a void procedure taking 1 argument, a
* TYPE_T_dictionary_binding pointer, which does not
* make any calls using dictionary d.
* Effects: Calls proc once with each binding in dictionary d.
* Order of bindings passed is undefined. Note that
* only the value field of the binding should be considered
* writable by proc.
*/
void TYPE_T_dictionary_Enumerate(TYPE_T_dictionary d,
void (*proc)(TYPE_T_dictionary_binding *))
{
int i;
TYPE_T_dictionary_binding *binding_ptr;
for (i=0; i<d->size; i++) {
binding_ptr = d->slots[i];
while (binding_ptr) {
proc(binding_ptr);
binding_ptr = binding_ptr->next;
}
}
}
/*
* Private routine:
*
* unsigned int dictionary__hash(char *s):
* Effects: Hashs s to an unsigned integer. This number mod the
* hash table size is supposed to roughly evenly distribute
* keys over the table's slots.
*/
static unsigned int
dictionary__hash(char *s)
{
unsigned int result = 0;
if (!s)
return(result);
while (s[0]) {
result <<= 1;
result += s[0];
s++;
}
return(result);
}
/*
* TYPE_T_dictionary_binding *TYPE_T_dictionary_Lookup(TYPE_T_dictionary d,
* char *key):
* Effects: If key is not bound in d, returns 0. Othersize,
* returns a pointer to the binding that binds key.
* Note the access restrictions on bindings...
*/
TYPE_T_dictionary_binding *
TYPE_T_dictionary_Lookup(TYPE_T_dictionary d,
char *key)
{
TYPE_T_dictionary_binding *binding_ptr;
binding_ptr = d->slots[dictionary__hash(key)%(d->size)];
while (binding_ptr) {
if (string_Eq(key, binding_ptr->key))
return(binding_ptr);
binding_ptr = binding_ptr->next;
}
return(NULL);
}
/*
* TYPE_T_dictionary_binding *TYPE_T_dictionary_Define(TYPE_T_dictionary d,
* char *key,
* int *already_existed):
* Modifies: d
* Effects: If key is bound in d, returns a pointer to the binding
* that binds key. Otherwise, adds a binding of key to
* d and returns its address. If already_existed is non-zero
* then *already_existed is set to 0 if key was not
* previously bound in d and 1 otherwise.
* Note the access restrictions on bindings... Note also
* that the value that key is bounded to if a binding is
* created is undefined. The caller should set the value
* in this case.
*/
TYPE_T_dictionary_binding *
TYPE_T_dictionary_Define(TYPE_T_dictionary d,
char *key,
int *already_existed)
{
TYPE_T_dictionary_binding **ptr_to_the_slot, *binding_ptr;
ptr_to_the_slot = &(d->slots[dictionary__hash(key)%(d->size)]);
binding_ptr = *ptr_to_the_slot;
while (binding_ptr) {
if (string_Eq(binding_ptr->key, key)) {
if (already_existed)
*already_existed = 1;
return(binding_ptr);
}
binding_ptr = binding_ptr->next;
}
if (already_existed)
*already_existed = 0;
binding_ptr = (TYPE_T_dictionary_binding *)malloc(
sizeof(TYPE_T_dictionary_binding));
binding_ptr->next = *ptr_to_the_slot;
binding_ptr->key = string_Copy(key);
*ptr_to_the_slot = binding_ptr;
return(binding_ptr);
}
/*
* void TYPE_T_dictionary_Delete(TYPE_T_dictionary d,
* TYPE_T_dictionary_binding *b):
* Requires: *b is a binding in d.
* Modifies: d
* Effects: Removes the binding *b from d. Note that if
* b->value needs to be freed, it should be freed
* before making this call.
*/
void TYPE_T_dictionary_Delete(TYPE_T_dictionary d,
TYPE_T_dictionary_binding *b)
{
TYPE_T_dictionary_binding **ptr_to_binding_ptr;
ptr_to_binding_ptr = &(d->slots[dictionary__hash(b->key)%(d->size)]);
while (*ptr_to_binding_ptr != b)
ptr_to_binding_ptr = &((*ptr_to_binding_ptr)->next);
*ptr_to_binding_ptr = b->next;
free(b->key);
free(b);
}

112
zwgc/dictionary.h Normal file
View File

@ -0,0 +1,112 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#ifndef TYPE_T_dictionary_TYPE
#define TYPE_T_dictionary_TYPE
typedef struct _TYPE_T_dictionary_binding {
struct _TYPE_T_dictionary_binding *next; /* PRIVATE */
char *key; /* READ-ONLY */
TYPE_T value;
} TYPE_T_dictionary_binding;
typedef struct _TYPE_T_dictionary { /* PRIVATE */
int size;
TYPE_T_dictionary_binding **slots;
} *TYPE_T_dictionary;
/*
* TYPE_T_dictionary TYPE_T_dictionary_Create(int size):
* Requires: size > 0
* Effects: Returns a new empty dictionary containing no bindings.
* The returned dictionary must be destroyed using
* TYPE_T_dictionary_Destroy. Size is a time vs space
* parameter. For this implementation, space used is
* proportional to size and time used is proportional
* to number of bindings divided by size. It is preferable
* that size is a prime number.
*/
extern TYPE_T_dictionary TYPE_T_dictionary_Create(int);
/*
* void TYPE_T_dictionary_Destroy(TYPE_T_dictionary d):
* Requires: d is a non-destroyed TYPE_T_dictionary
* Modifies: d
* Effects: Destroys dictionary d freeing up the space it consumes.
* Dictionary d should never be referenced again. Note that
* free is NOT called on the values of the bindings. If
* this is needed, the client must do this first using
* TYPE_T_dictionary_Enumerate.
*/
extern void TYPE_T_dictionary_Destroy(TYPE_T_dictionary);
/*
* void TYPE_T_dictionary_Enumerate(TYPE_T_dictionary d;
* void (*proc)(TYPE_T_dictionary_binding *b)):
* Requires: proc is a void procedure taking 1 argument, a
* TYPE_T_dictionary_binding pointer, which does not
* make any calls using dictionary d.
* Effects: Calls proc once with each binding in dictionary d.
* Order of bindings passed is undefined. Note that
* only the value field of the binding should be considered
* writable by proc.
*/
extern void TYPE_T_dictionary_Enumerate(TYPE_T_dictionary, void (*)(TYPE_T_dictionary_binding *));
/*
* TYPE_T_dictionary_binding *TYPE_T_dictionary_Lookup(TYPE_T_dictionary d,
* char *key):
* Effects: If key is not bound in d, returns 0. Othersize,
* returns a pointer to the binding that binds key.
* Note the access restrictions on bindings...
*/
extern TYPE_T_dictionary_binding *TYPE_T_dictionary_Lookup(TYPE_T_dictionary,
char *);
/*
* TYPE_T_dictionary_binding *TYPE_T_dictionary_Define(TYPE_T_dictionary d,
* char *key,
* int *already_existed):
* Modifies: d
* Effects: If key is bound in d, returns a pointer to the binding
* that binds key. Otherwise, adds a binding of key to
* d and returns its address. If already_existed is non-zero
* then *already_existed is set to 0 if key was not
* previously bound in d and 1 otherwise.
* Note the access restrictions on bindings... Note also
* that the value that key is bounded to if a binding is
* created is undefined. The caller should set the value
* in this case.
*/
extern TYPE_T_dictionary_binding *TYPE_T_dictionary_Define(TYPE_T_dictionary,
char *, int *);
/*
* void TYPE_T_dictionary_Delete(TYPE_T_dictionary d,
* TYPE_T_dictionary_binding *b):
* Requires: *b is a binding in d.
* Modifies: d
* Effects: Removes the binding *b from d. Note that if
* b->value needs to be freed, it should be freed
* before making this call.
*/
extern void TYPE_T_dictionary_Delete(TYPE_T_dictionary,
TYPE_T_dictionary_binding *);
#endif

22
zwgc/error.c Normal file
View File

@ -0,0 +1,22 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_error_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
int error_code;

59
zwgc/error.h Normal file
View File

@ -0,0 +1,59 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef error_MODULE
#define error_MODULE
#include <stdio.h>
#include <errno.h>
#include <zephyr/zephyr.h>
extern int error_code;
#define FATAL_TRAP(function_call, message) \
{ error_code = (function_call);\
if (error_code) {\
com_err("zwgc", error_code,\
message);\
exit(3);\
}\
}
#define TRAP(function_call, message) \
{ error_code = (function_call);\
if (error_code) {\
com_err("zwgc", error_code,\
message);\
}\
}
#define ERROR(a) { fprintf(stderr, "zwgc: "); \
fprintf(stderr, a);\
fflush(stderr); }
#define ERROR2(a,b) { fprintf(stderr, "zwgc: "); \
fprintf(stderr, a, b);\
fflush(stderr); }
#define ERROR3(a,b,c) { fprintf(stderr, "zwgc: "); \
fprintf(stderr, a, b, c);\
fflush(stderr); }
#define ERROR4(a,b,c,d) { fprintf(stderr, "zwgc: "); \
fprintf(stderr, a, b, c, d);\
fflush(stderr); }
#endif

300
zwgc/eval.c Normal file
View File

@ -0,0 +1,300 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_eval_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* Code to evaluate an expression: */
/* */
/****************************************************************************/
#include <zephyr/zephyr.h>
#include "new_memory.h"
#include "node.h"
#include "eval.h"
#include "substitute.h"
#include "port.h"
#include "buffer.h"
#include "regexp.h"
#include "formatter.h"
#include "text_operations.h"
#include "zwgc.h"
#include "variables.h"
/****************************************************************************/
/* */
/* Code to deal with string/boolean conversion: */
/* */
/****************************************************************************/
/*
* Internal Routine:
*
* int string_to_bool(string str)
* Effects: Returns true iff the string str represents true.
* True is represented by any string which is equal to
* "true" when case is disregraded.
*/
#define string_to_bool(str) (!strcasecmp(str,"true"))
/*
* Internal Routine:
*
* string bool_to_string(int bool)
* Effects: Returns a string representive for the C boolean bool.
* (In C, true == non-zero) I.e.,
* string_to_bool(bool_to_string(x)) == !!x.
* The string returned is on the heap & must be freed
* eventually.
*/
static string
bool_to_string(int bool)
{
return(bool ? string_Copy("TRUE") : string_Copy("FALSE"));
}
/*
* int eval_bool_expr(Node *expr)
* Modifies: dict
* Requires: expr is a proper expression or NULL. (see node.c)
* Effects: Evaluates expr to its boolean value which is returned.
* NULL is defined to have the boolean value true.
*/
int
eval_bool_expr(Node *expr)
{
string temp;
int result;
if (!expr)
return(1);
temp = eval_expr(expr);
result = string_to_bool(temp);
free(temp);
return(result);
}
/****************************************************************************/
/* */
/* Code to evaluate an expression: */
/* */
/****************************************************************************/
/*
* string eval_expr(Node *expr)
* Modifies: dict
* Requires: expr is a proper expression (NOT NULL). (see node.c)
* Effects: Evaluates expr to its string value which is returned.
* The returned string is on the heap and must be freed
* eventually.
*/
string
eval_expr(Node *expr)
{
int opcode = expr->opcode;
int bool_result = 0;
string first, second;
char *result = NULL;
string *text_ptr;
/*
* Dispatch based on the opcode of the top node in the expression:
*/
switch (opcode) {
case STRING_CONSTANT_OPCODE:
return(string_Copy(expr->d.string_constant));
case VARREF_OPCODE:
return(string_Copy(var_get_variable(expr->d.string_constant)));
case BUFFER_OPCODE:
return(string_Copy(buffer_to_string()));
/*
* Handle unary expressions:
*/
case NOT_OPCODE:
case SUBSTITUTE_OPCODE:
case PROTECT_OPCODE:
case VERBATIM_OPCODE:
case STYLESTRIP_OPCODE:
case GETENV_OPCODE:
case UPCASE_OPCODE:
case DOWNCASE_OPCODE:
case ZVAR_OPCODE:
case GET_OPCODE:
first = eval_expr(expr->d.nodes.first);
switch (opcode) {
case NOT_OPCODE:
result = bool_to_string(! string_to_bool(first));
break;
case SUBSTITUTE_OPCODE:
result = substitute(var_get_variable, first);
break;
case PROTECT_OPCODE:
result=protect(first);
break;
case VERBATIM_OPCODE:
return(verbatim(first,0));
case STYLESTRIP_OPCODE:
return(stylestrip(first));
case GETENV_OPCODE:
result = getenv(first);
if (!result)
result = string_Copy("");
else
result = string_Copy(result);
break;
case UPCASE_OPCODE:
return(string_Upcase(first));
case DOWNCASE_OPCODE:
return(string_Downcase(first));
case ZVAR_OPCODE:
result = ZGetVariable(first);
if (!result)
result = string_Copy("");
else
result = string_Copy(result);
break;
case GET_OPCODE:
result = read_from_port(first);
break;
}
free(first);
break;
/*
* Handle binary operators:
*/
case PLUS_OPCODE:
case AND_OPCODE:
case OR_OPCODE:
case EQ_OPCODE:
case NEQ_OPCODE:
case REGEQ_OPCODE:
case REGNEQ_OPCODE:
first = eval_expr(expr->d.nodes.first);
second = eval_expr(expr->d.nodes.second);
switch (opcode) {
case PLUS_OPCODE:
result = string_Concat(first, second);
free(first);
free(second);
return(result);
case AND_OPCODE:
bool_result = string_to_bool(first) && string_to_bool(second);
break;
case OR_OPCODE:
bool_result = string_to_bool(first) || string_to_bool(second);
break;
case EQ_OPCODE:
bool_result = string_Eq(first, second);
break;
case NEQ_OPCODE:
bool_result = string_Neq(first, second);
break;
case REGEQ_OPCODE:
bool_result = ed_regexp_match_p(first, second);
break;
case REGNEQ_OPCODE:
bool_result = !ed_regexp_match_p(first, second);
break;
}
free(first);
free(second);
result = bool_to_string(bool_result);
break;
/*
* Handle text-manipulation operators:
*/
case LANY_OPCODE: case RANY_OPCODE:
case LBREAK_OPCODE: case RBREAK_OPCODE:
case LSPAN_OPCODE: case RSPAN_OPCODE:
first = eval_expr(expr->d.nodes.first);
second = eval_expr(expr->d.nodes.second);
text_ptr = &first;
switch (opcode) {
case LANY_OPCODE:
result = lany(text_ptr, second);
break;
case RANY_OPCODE:
result = rany(text_ptr, second);
break;
case LBREAK_OPCODE:
result = lbreak(text_ptr, string_to_character_class(second));
break;
case RBREAK_OPCODE:
result = rbreak(text_ptr, string_to_character_class(second));
break;
case LSPAN_OPCODE:
result = lspan(text_ptr, string_to_character_class(second));
break;
case RSPAN_OPCODE:
result = rspan(text_ptr, string_to_character_class(second));
break;
}
if (expr->d.nodes.first->opcode == VARREF_OPCODE)
var_set_variable(expr->d.nodes.first->d.string_constant, first);
free(first);
free(second);
break;
#ifdef DEBUG
default:
printf("zwgc: internal error: attempt to evaluate the following non-expression:\n"); fflush(stdout);
node_display(expr);
printf("\n\n");
exit(2);
#endif
}
return(result);
}

43
zwgc/eval.h Normal file
View File

@ -0,0 +1,43 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef eval_MODULE
#define eval_MODULE
#include "new_string.h"
/*
* string eval_expr(Node *expr)
* Modifies: dict
* Requires: expr is a proper expression (NOT NULL). (see node.c)
* Effects: Evaluates expr to its string value which is returned.
* The returned string is on the heap and must be freed
* eventually.
*/
extern string eval_expr(Node *);
/*
* int eval_bool_expr(Node *expr)
* Modifies: dict
* Requires: expr is a proper expression or NULL. (see node.c)
* Effects: Evaluates expr to its boolean value which is returned.
* NULL is defined to have the boolean value true.
*/
extern int eval_bool_expr(Node *);
#endif

482
zwgc/exec.c Normal file
View File

@ -0,0 +1,482 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_exec_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* Module containing code to execute a program: */
/* */
/****************************************************************************/
#include <zephyr/zephyr.h>
#include "new_memory.h"
#include "node.h"
#include "exec.h"
#include "eval.h"
#include "buffer.h"
#include "port.h"
#include "variables.h"
#include "notice.h"
#ifdef CMU_ZWGCPLUS
#include "plus.h"
#endif
static int exec_subtree(Node *);
static int exec_fields(Node *);
/****************************************************************************/
/* */
/* Utility subroutines: */
/* */
/****************************************************************************/
static string
eval_exprlist_to_string(Node *exprlist)
{
string result = string_Copy("");
string temp;
int first_time = 1;
for (; exprlist; exprlist=exprlist->next) {
if (!first_time)
result = string_Concat2(result, " ");
else
first_time = 0;
temp = eval_expr(exprlist);
result = string_Concat2(result, temp);
free(temp);
}
return(result);
}
static char **
eval_exprlist_to_args(Node *exprlist)
{
char **result = (char **)malloc(sizeof(char *));
int argc = 0;
for (; exprlist; exprlist=exprlist->next) {
result[argc] = eval_expr(exprlist);
argc++;
result = (char **)realloc(result, (argc+1)*sizeof(char *));
}
result[argc] = NULL;
return(result);
}
static void
free_args(char **args)
{
char **p;
for (p=args; *p; p++) {
free(*p);
}
free(args);
}
/****************************************************************************/
/* */
/* Subroutines to handle each particular statement type: */
/* */
/****************************************************************************/
#define NOBREAK 0
#define BREAK 1
#define EXIT 2
/*ARGSUSED*/
static int
exec_noop(Node *node)
{
return(NOBREAK);
}
/*ARGSUSED*/
static int
exec_break(Node *node)
{
return(BREAK);
}
/*ARGSUSED*/
static int
exec_exit(Node *node)
{
return(EXIT);
}
static int
exec_set(Node *node)
{
var_set_variable_then_free_value(node->d.nodes.first->d.string_constant,
eval_expr(node->d.nodes.second));
return(NOBREAK);
}
static int
exec_execport(Node *node)
{
string name = eval_expr(node->d.nodes.first);
char **argv = eval_exprlist_to_args(node->d.nodes.second);
create_subprocess_port(name, argv);
free(name);
free_args(argv);
return(NOBREAK);
}
static int
exec_appendport(Node *node)
{
string name, filename;
name = eval_expr(node->d.nodes.first);
filename = eval_expr(node->d.nodes.second);
create_file_append_port(name, filename);
free(name);
free(filename);
return(NOBREAK);
}
static int
exec_inputport(Node *node)
{
string name, filename;
name = eval_expr(node->d.nodes.first);
filename = eval_expr(node->d.nodes.second);
create_file_input_port(name, filename);
free(name);
free(filename);
return(NOBREAK);
}
static int
exec_outputport(Node *node)
{
string name, filename;
name = eval_expr(node->d.nodes.first);
filename = eval_expr(node->d.nodes.second);
create_file_output_port(name, filename);
free(name);
free(filename);
return(NOBREAK);
}
static int
exec_closeinput(Node *node)
{
string name;
name = eval_expr(node->d.nodes.first);
close_port_input(name);
free(name);
return(NOBREAK);
}
static int
exec_closeoutput(Node *node)
{
string name;
name = eval_expr(node->d.nodes.first);
close_port_output(name);
free(name);
return(NOBREAK);
}
static int
exec_closeport(Node *node)
{
string name;
name = eval_expr(node->d.nodes.first);
close_port_input(name);
close_port_output(name);
free(name);
return(NOBREAK);
}
static int
exec_put(Node *node)
{
string name, temp;
if (node->d.nodes.second)
temp = eval_exprlist_to_string(node->d.nodes.second);
else
temp = string_Copy(buffer_to_string());
if (node->d.nodes.first) {
name = eval_expr(node->d.nodes.first);
write_on_port(name, temp, strlen(temp));
free(name);
} else
write_on_port(var_get_variable("output_driver"), temp, strlen(temp));
free(temp);
return(NOBREAK);
}
static int
exec_print(Node *node)
{
string temp;
temp = eval_exprlist_to_string(node->d.nodes.first);
append_buffer(temp);
free(temp);
return(NOBREAK);
}
/*ARGSUSED*/
static int
exec_clearbuf(Node *node)
{
clear_buffer();
return(NOBREAK);
}
static int
exec_case(Node *node)
{
string constant,temp;
Node *match, *cond;
int equal_p;
constant = string_Downcase(eval_expr(node->d.nodes.first));
for (match=node->d.nodes.second; match; match=match->next) {
cond = match->d.nodes.first;
if (!cond) { /* default case */
free(constant);
return(exec_subtree(match->d.nodes.second));
}
for (; cond; cond=cond->next) {
temp = string_Downcase(eval_expr(cond));
equal_p = string_Eq(constant, temp);
free(temp);
if (equal_p) {
free(constant);
return(exec_subtree(match->d.nodes.second));
}
}
}
free(constant);
return(NOBREAK);
}
static int
exec_while(Node *node)
{
int continue_code = NOBREAK;
while (eval_bool_expr(node->d.nodes.first)) {
continue_code = exec_subtree(node->d.nodes.second);
if (continue_code != NOBREAK)
break;
}
if (continue_code == BREAK)
continue_code = NOBREAK;
return(continue_code);
}
static int
exec_if(Node *node)
{
Node *conds;
for (conds=node->d.nodes.first; conds; conds=conds->next)
if (eval_bool_expr(conds->d.nodes.first))
return(exec_subtree(conds->d.nodes.second));
return(NOBREAK);
}
static int
exec_exec(Node *node)
{
int pid;
char **argv = eval_exprlist_to_args(node->d.nodes.first);
pid = fork();
if (pid == -1) {
fprintf(stderr, "zwgc: error while attempting to fork: ");
perror("");
} else if (pid == 0) { /* in child */
execvp(argv[0], argv);
fprintf(stderr,"zwgc: unable to exec %s: ", argv[0]);
perror("");
_exit(errno);
}
free_args(argv);
return(NOBREAK);
}
static struct _Opstuff {
int (*exec)(Node *);
} const opstuff[] = {
{ exec_noop }, /* string_constant */
{ exec_noop }, /* varref */
{ exec_noop }, /* varname */
{ exec_noop }, /* not */
{ exec_noop }, /* plus */
{ exec_noop }, /* and */
{ exec_noop }, /* or */
{ exec_noop }, /* eq */
{ exec_noop }, /* neq */
{ exec_noop }, /* regeq */
{ exec_noop }, /* regneq */
{ exec_noop }, /* buffer */
{ exec_noop }, /* substitute */
{ exec_noop }, /* protect */
{ exec_noop }, /* verbatim */
{ exec_noop }, /* stylestrip */
{ exec_noop }, /* getenv */
{ exec_noop }, /* upcase */
{ exec_noop }, /* downcase */
{ exec_noop }, /* zvar */
{ exec_noop }, /* get */
{ exec_noop }, /* lany */
{ exec_noop }, /* rany */
{ exec_noop }, /* lbreak */
{ exec_noop }, /* rbreak */
{ exec_noop }, /* lspan */
{ exec_noop }, /* rspan */
{ exec_noop }, /* noop statement */
{ exec_set },
{ exec_fields },
{ exec_print },
{ exec_clearbuf },
{ exec_appendport },
{ exec_execport },
{ exec_inputport },
{ exec_outputport },
{ exec_put },
{ exec_closeinput },
{ exec_closeoutput },
{ exec_closeport },
{ exec_exec },
{ exec_if },
{ exec_case },
{ exec_while },
{ exec_break },
{ exec_exit },
{ exec_noop }, /* if */
{ exec_noop }, /* elseif */
{ exec_noop }, /* else */
{ exec_noop }, /* matchlist */
{ exec_noop }, /* default */
};
static int
exec_subtree(Node *node)
{
int retval = NOBREAK;
for (; node; node=node->next) {
retval = (opstuff[node->opcode].exec)(node);
if (retval != NOBREAK)
return(retval);
}
return(NOBREAK);
}
/***************************************************************************/
static char *notice_fields;
static int notice_fields_length = 0;
static int number_of_fields = 0;
static int
exec_fields(Node *node)
{
for (node=node->d.nodes.first; node; node=node->next) {
var_set_variable_then_free_value(node->d.string_constant,
get_next_field(&notice_fields,
&notice_fields_length));
if (number_of_fields)
number_of_fields--;
}
var_set_variable_to_number("number_of_fields", number_of_fields);
return(NOBREAK);
}
void
exec_process_packet(Node *program,
ZNotice_t *notice)
{
#ifdef CMU_ZWGCPLUS
set_stored_notice(notice);
#endif
notice_fields = notice->z_message;
notice_fields_length = notice->z_message_len;
var_set_number_variables_to_fields(notice_fields, notice_fields_length);
number_of_fields = count_nulls(notice_fields, notice_fields_length)+1;
/* workaround for bug in old zwrite */
if (notice_fields[notice_fields_length-1] == '\0')
number_of_fields--;
var_set_variable_to_number("number_of_fields", number_of_fields);
clear_buffer();
(void)exec_subtree(program);
#ifdef CMU_ZWGCPLUS
plus_queue_notice(notice);
plus_window_deletions(notice); /* OOPS */
set_stored_notice(NULL);
#endif
}

22
zwgc/exec.h Normal file
View File

@ -0,0 +1,22 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef exec_MODULE
#define exec_MODULE
extern void exec_process_packet(Node *, ZNotice_t *);
#endif

119
zwgc/file.c Normal file
View File

@ -0,0 +1,119 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_file_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
#include <pwd.h>
#include "new_memory.h"
#include "new_string.h"
#include "error.h"
#include "file.h"
/*
* char *get_home_directory()
*
* Effects: Attempts to locate the user's (by user, the owner of this
* process is meant) home directory & return its pathname.
* Returns NULL if unable to do so. Does so by first checking
* the environment variable HOME. If it is unset, falls back
* on the user's password entry.
* Note: The returned pointer may point to a static buffer & hence
* go away on further calls to getenv, get_home_directory,
* getpwuid, or related calls. The caller should copy it
* if necessary.
*/
static char
*get_home_directory(void)
{
char *result;
struct passwd *passwd_entry;
result = getenv("HOME");
if (result)
return(result);
if (!(passwd_entry = getpwuid(getuid())))
return(NULL);
return(passwd_entry->pw_dir);
}
/*
*
*/
FILE *locate_file(char *override_filename,
char *home_dir_filename,
char *fallback_filename)
{
char *filename;
FILE *result;
errno = 0;
if (override_filename) {
if (string_Eq(override_filename, "-"))
return(stdin);
result = fopen(override_filename, "r");
if (!(result = fopen(override_filename, "r"))) {
/* <<<>>> */
fprintf(stderr, "zwgc: error while opening %s for reading: ",
override_filename);
perror("");
}
return(result);
}
if (home_dir_filename) {
filename = get_home_directory();
if (filename) {
filename = string_Concat(filename, "/");
filename = string_Concat2(filename, home_dir_filename);
result = fopen(filename, "r");
if (result) {
free(filename);
return(result);
}
if (errno != ENOENT) {
/* <<<>>> */
fprintf(stderr, "zwgc: error while opening %s for reading: ",
filename);
perror("");
free(filename);
return(result);
}
free(filename);
} else
ERROR("unable to find your home directory.\n");
}
if (fallback_filename) {
if (!(result = fopen(fallback_filename, "r"))) {
/* <<<>>> */
fprintf(stderr, "zwgc: error while opening %s for reading: ",
fallback_filename);
perror("");
}
return(result);
}
return(NULL);
}

24
zwgc/file.h Normal file
View File

@ -0,0 +1,24 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef file_MODULE
#define file_MODULE
#include <stdio.h>
extern FILE *locate_file(char *, char *, char *);
#endif

562
zwgc/formatter.c Normal file
View File

@ -0,0 +1,562 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_formatter_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
#include <zephyr/zephyr.h>
#include "new_memory.h"
#include "char_stack.h"
#include "string_dictionary.h"
#include "formatter.h"
#include "text_operations.h"
#if !defined(__STDC__) && !defined(const)
#define const
#endif
static int pure_text_length(char *, char);
static int env_length(char *);
#ifdef notdef
static character_class atsign_set = { /* '@' = 0x40 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
#endif
static const character_class paren_set = { /* '(' = 0x28, ')' = 0x29 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
static const character_class sbracket_set = { /* '[' = 0x5b, ']' = 0x5d */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
static const character_class abracket_set = { /* '<' = 0x3c, '>' = 0x3e */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
static const character_class cbracket_set = { /* '{' = 0x7b, '}' = 0x7d */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
static const character_class allbracket_set = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
static const character_class allmaskable_set = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
static char brackets[]="()<>[]{}@";
static char *openbracket[]={"@<","@<","@[","@[","@{","@{","@(","@(","@("};
static char *closebracket[]={">",">","]","]","}","}",")",")",")"};
static int
not_contains(string str,
const character_class set)
{
while (*str && ! set[(int)*str]) str++;
return (! *str);
}
static int
pure_text_length(char *text,
char terminator)
{
int len=0;
while (1) {
while (*text!='@' && *text!=terminator && *text) {
text++;
len++;
}
if (*text!='@')
return(len);
if (*(text+1)=='@') {
text++;
len++;
} else if (env_length(text+1) != -1)
return(len);
text++;
len++;
}
}
static char
otherside(char opener)
{
switch (opener) {
case '(':
return(')');
case '{':
return('}');
case '[':
return(']');
case '<':
return('>');
}
#ifdef DEBUG
abort();
#endif
return 0;
}
/* the char * that str points to is free'd by this function.
* if you want to keep it, save it yourself
*/
string
verbatim(string str, int bracketsonly)
{
char *temp,*temp2;
int bracketnum,len;
len = strlen(str);
if (len == pure_text_length(str,0)) {
/* No environments, so consider the fast-and-easy methods */
if (not_contains(str,allbracket_set)) {
temp = string_Copy(str);
free(str);
return(temp);
}
if (not_contains(str,abracket_set)) {
temp=(char *) malloc((len=strlen(str))+4);
temp[0]='@';
temp[1]='<';
(void) memcpy(temp+2,str,len);
temp[len+2]='>';
temp[len+3]='\0';
free(str);
return(temp);
}
if (not_contains(str,sbracket_set)) {
temp=(char *) malloc((len=strlen(str))+4);
temp[0]='@';
temp[1]='[';
(void) memcpy(temp+2,str,len);
temp[len+2]=']';
temp[len+3]='\0';
free(str);
return(temp);
}
if (not_contains(str,cbracket_set)) {
temp=(char *) malloc((len=strlen(str))+4);
temp[0]='@';
temp[1]='{';
(void) memcpy(temp+2,str,len);
temp[len+2]='}';
temp[len+3]='\0';
free(str);
return(temp);
}
if (not_contains(str,paren_set)) {
temp=(char *) malloc((len=strlen(str))+4);
temp[0]='@';
temp[1]='(';
(void) memcpy(temp+2,str,len);
temp[len+2]=')';
temp[len+3]='\0';
free(str);
return(temp);
}
}
temp=lbreak(&str,bracketsonly?allbracket_set:allmaskable_set);
while(*str) {
bracketnum=(int) (strchr(brackets,str[0])-brackets);
temp=string_Concat2(temp,openbracket[bracketnum]);
temp=string_Concat2(temp,temp2=lany(&str," "));
free(temp2);
temp=string_Concat2(temp,closebracket[bracketnum]);
temp=string_Concat2(temp,temp2=lbreak(&str,bracketsonly?
allbracket_set:allmaskable_set));
free(temp2);
}
free(str); /* str is "" at this point, anyway */
return(temp);
}
/* text points to beginning of text string. return value is
length of string, up to but not including the passed terminator
or the default terminator \0. The text will not be modified,
and @@ will be counted twice */
string
protect(string str)
{
string temp,temp2,temp3;
int len,templen;
char_stack chs;
char tos;
temp = string_Copy("");
templen = 1;
chs = char_stack_create();
while(*str) {
tos = (char_stack_empty(chs)?0:char_stack_top(chs));
if (*str == tos) {
/* if the character is the next terminator */
temp = (char *) realloc(temp,++templen);
temp[templen-2] = *str++;
char_stack_pop(chs);
temp[templen-1] = '\0';
} else if ((len = pure_text_length(str,tos))) {
if (tos) {
/* if the block is text in an environment, just copy it */
temp2 = string_CreateFromData(str,len);
str += len;
temp = string_Concat2(temp,temp2);
templen += len;
free(temp2);
} else {
/* if the block is top level text, verbatim brackets only
(not @'s) and add text to temp */
temp2 = string_CreateFromData(str,len);
str += len;
temp3 = verbatim(temp2,1);
temp = string_Concat2(temp,temp3);
templen += strlen(temp3);
free(temp3);
}
} else {
/* if the block is an environment, copy it, push delimiter */
len = env_length(str+1);
char_stack_push(chs,otherside(str[len+1]));
len += 2;
temp2 = string_CreateFromData(str,len);
str += len;
temp = string_Concat2(temp,temp2);
templen += len;
free(temp2);
}
}
/* all blocks have been copied. */
while (!char_stack_empty(chs)) {
temp = (char *) realloc(temp,++templen);
temp[templen-2] = char_stack_top(chs);
char_stack_pop(chs);
}
temp[templen-1] = '\0';
return(temp);
}
/* str points to a string. return value is another string
which is the original with all styles removed. */
string
stylestrip(string str)
{
int templen = 0, otherchar;
char *temp = (char *) malloc(string_Length(str) + 1);
char_stack chs;
string ostr = str;
chs = char_stack_create();
while (*str) {
if (*str == '@') {
int len = env_length(str + 1);
if (len != -1) {
otherchar = 0;
if ((len == 4 && !strncasecmp(str + 1, "font", 4))
|| (len == 5 && !strncasecmp(str + 1, "color", 5)))
otherchar = 0x80;
otherchar |= otherside(str[len + 1]);
char_stack_push(chs, otherchar);
str += len + 2;
continue;
}
}
if (!char_stack_empty(chs) && *str == (char_stack_top(chs) & 0x7f)) {
char_stack_pop(chs);
str++;
continue;
}
if (!char_stack_empty(chs) && (char_stack_top(chs) & 0x80))
str++;
else
temp[templen++] = *str++;
}
temp[templen] = 0;
while (!char_stack_empty(chs))
char_stack_pop(chs);
free(ostr);
return(temp);
}
void
free_desc(desctype *desc)
{
desctype *next_desc;
while (desc->code != DT_EOF) {
next_desc = desc->next;
free(desc);
desc = next_desc;
}
free(desc);
}
/* text points to beginning of possible env name. return value is
length of env name, not including @ or opener, or -1 if not a
possible env name. */
static int
env_length(char *text)
{
int len=0;
while (*text && (isalnum(*text) || *text=='_')) {
text++;
len++;
}
if ((*text=='(') || (*text=='{') || (*text=='[') || (*text=='<'))
return(len);
else
return(-1);
}
/* text points to beginning of text string. return value is
length of string, up to but not including the passed terminator
or the default terminators \0 \n @. This can modify text, and 0
is a valid return value. */
static int
text_length(char *text,
char terminator)
{
int len=0;
while (1) {
while (*text!='@' && *text!='\n' && *text!=terminator && *text) {
text++;
len++;
}
if (*text!='@')
return(len);
if (*(text+1)=='@')
(void) memmove(text+1,text+2,strlen(text+1));
else if (env_length(text+1) != -1)
return(len);
text++;
len++;
}
}
/* parses str into a desc linked list. Returns number of strings and
newlines in *pstr and *pnl */
desctype *
disp_get_cmds(char *str,
int *pstr,
int *pnl)
{
desctype *desc,*here;
int len;
char_stack terminators = char_stack_create();
char terminator;
int nstr=0, nnl=0;
char *curstr;
desc=(desctype *) malloc(sizeof(desctype));
here=desc;
curstr=str;
terminator = '\0';
while (*curstr) {
if (*curstr=='\n') {
here->code=DT_NL;
curstr++;
nnl++;
} else if (*curstr==terminator) { /* if this is the end of an env */
here->code=DT_END;
terminator = char_stack_top(terminators);
char_stack_pop(terminators);
curstr++;
} else if ((len=text_length(curstr, terminator))) { /* if there is a text
block here */
here->code=DT_STR;
here->str=curstr;
here->len=len;
curstr+=len;
nstr++;
} else if (*curstr=='@') { /* if this is the beginning of an env */
len=env_length(curstr+1);
here->code=DT_ENV;
here->str=curstr+1;
here->len=len;
char_stack_push(terminators, terminator);
terminator=otherside(*(curstr+1+len));
curstr+=(len+2); /* jump over @, env name, and opener */
}
here->next=(desctype *) malloc(sizeof(desctype));
here=here->next;
}
while (!char_stack_empty(terminators)) {
here->code=DT_END;
terminator = char_stack_top(terminators);
char_stack_pop(terminators);
here->next=(desctype *) malloc(sizeof(desctype));
here=here->next;
}
here->code=DT_EOF;
*pstr=nstr;
*pnl=nnl;
#ifdef DEBUG_PRINTOUT
{ string temp;
here = desc;
while (here->code != DT_EOF) {
if (here->code == DT_STR || here->code == DT_ENV) {
temp = string_CreateFromData(here->str, here->len);
printf("[%d <%s>]\n", here->code, temp);
free(temp);
} else
printf("[%d]\n", here->code);
here=here->next;
}
}
#endif
return(desc);
}

43
zwgc/formatter.h Normal file
View File

@ -0,0 +1,43 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#include "new_string.h"
#ifndef formatter_MODULE
#define formatter_MODULE
typedef struct _desctype {
struct _desctype *next;
short int code;
#define DT_EOF 0 /* End of message. */
#define DT_ENV 1 /* Open environment. */
#define DT_STR 2 /* Display string. */
#define DT_END 3 /* Close environment. */
#define DT_NL 4 /* Newline. */
char *str; /* Name of environment, string to be displayed. */
int len; /* Length of string/environment name for
ENV, STR, END. Undefined for EOF */
} desctype;
extern desctype *disp_get_cmds(char *, int *, int *);
extern void free_desc(desctype *);
extern string protect(string);
extern string verbatim(string, int);
extern string stylestrip(string);
#endif

39
zwgc/instantiate Executable file
View File

@ -0,0 +1,39 @@
#!/bin/sh -
# This file is part of the Project Athena Zephyr Notification System.
# It is one of the source files comprising zwgc, the Zephyr WindowGram
# client.
#
# $Id$
#
# Copyright (c) 1989,1993 by the Massachusetts Institute of Technology.
# For copying and distribution information, see the file
# "mit-copyright.h".
#
if [ "$1" = "" ]; then
echo "Usage: generate_instance <srcdir> <type> <name> [<include file>]"
exit 1
fi
source=$1
type=$2
name=$3
incfile=$4
if [ "$type" != "stack" ]; then
if [ ! -f ${source}/${type}.c ]; then
echo "$0: unable to open ${source}/${type}.c"
exit 2
fi
sed "s/TYPE_T/$name/g" ${source}/${type}.c > ${name}_${type}.c
fi
if [ "$incfile" != "" ]; then
echo "#include \"$incfile\"" > ${name}_${type}.h
fi
if [ ! -f ${source}/${type}.h ]; then
echo "$0: unable to open ${source}/${type}.h"
exit 2
fi
sed "s/TYPE_T/$name/g" ${source}/${type}.h >> ${name}_${type}.h

673
zwgc/lexer.c Normal file
View File

@ -0,0 +1,673 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_lexer_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* The lexer for the zwgc description language: */
/* */
/****************************************************************************/
#include "new_memory.h"
#include "new_string.h"
#include "int_dictionary.h"
#include "lexer.h"
#include "parser.h"
#include "y.tab.h"
/*
* yylineno - this holds the current line # we are on. Updated automatically
* by input() and unput().
*/
int yylineno;
/*
* keyword_dict - this dictionary maps keyword names to their token numbers.
*/
static int_dictionary keyword_dict = NULL;
/****************************************************************************/
/* */
/* I/O functions: */
/* */
/****************************************************************************/
/*
* input_file - this holds the FILE pointer to the file currently being lexed.
*/
static FILE *input_file;
/*
* pushback - if not -1, holds a character that was pushed back by unput but
* not yet read by input.
*/
static int pushback = -1;
static char
input(void)
{
int c;
if (pushback != -1) {
c = pushback;
pushback = -1;
if (c=='\n')
yylineno++;
return(c);
}
c = getc(input_file);
if (c=='\n')
yylineno++;
if (c==EOF)
c = 0;
return(c);
}
static void
unput(int c)
{
#ifdef DEBUG
if (pushback != -1) {
printf("Attempt to push back 2 characters at one time!\n");
exit(1);
}
#endif
pushback = c;
if (c == '\n')
yylineno--;
}
/****************************************************************************/
/* */
/* Initialization routines: */
/* */
/****************************************************************************/
struct keyword_info {
string keyword;
int keyword_number;
};
/*
* keywords - This table holds a copy of the mapping from keyword name to
* token number and is used to initialize keyword_dict:
*/
static struct keyword_info keywords[] = {
{ "and", '&' },
{ "appendport", APPENDPORT },
{ "buffer", BUFFER },
{ "break", BREAK },
{ "closeinput", CLOSEINPUT },
{ "closeoutput", CLOSEOUTPUT },
{ "closeport", CLOSEPORT },
{ "case", CASE },
{ "clearbuf", CLEARBUF },
{ "default", DEFAULT },
{ "do", DO },
{ "downcase", DOWNCASE },
{ "else", ELSE },
{ "elseif", ELSEIF },
{ "endcase", ENDCASE },
{ "endif", ENDIF },
{ "endwhile", ENDWHILE },
{ "exec", EXEC },
{ "execport", EXECPORT },
{ "exit", EXIT },
{ "fields", FIELDS },
{ "get", GET },
{ "getenv", GETENV },
{ "if", IF },
{ "inputport", INPUTPORT },
{ "lany", LANY },
{ "lbreak", LBREAK },
{ "lspan", LSPAN },
{ "match", MATCH },
{ "noop", NOOP },
{ "not", '!' },
{ "or", '|' },
{ "outputport", OUTPUTPORT },
{ "print", PRINT },
{ "protect", PROTECT },
{ "put", PUT },
{ "rany", RANY },
{ "rbreak", RBREAK },
{ "rspan", RSPAN },
{ "set", SET },
{ "show", SHOW },
{ "stylestrip", STYLESTRIP },
{ "substitute", SUBSTITUTE },
{ "then", THEN },
{ "upcase", UPCASE },
{ "while", WHILE },
{ "verbatim", VERBATIM },
{ "zvar", ZVAR } };
/*
* lex_open - this routine [re]initializes the lexer & prepares it to lex
* a file. Resets current line # to 1.
*/
void
lex_open(FILE *file)
{
/*
* Initialize I/O:
*/
input_file = file;
yylineno = 1;
pushback = -1;
/*
* Initialize keyword_dict from keywords if needed:
*/
if (!keyword_dict) {
unsigned int i;
keyword_dict = int_dictionary_Create(101);
for (i=0; i<sizeof(keywords)/sizeof(struct keyword_info); i++)
int_dictionary_Define(keyword_dict, keywords[i].keyword,
0)->value = keywords[i].keyword_number;
}
}
/****************************************************************************/
/* */
/* lex subroutines: */
/* */
/****************************************************************************/
/*
* eat_escape_code - this rountine eats an escape code & returns the character
* it codes for or 0 if it codes for "".
* (an escape code is what follows a '\\' in a quoted
* string) Current escape codes are:
*
* "n" == '\n'
* "t" == '\t'
* "b" == '\b'
* "\n" == "" (i.e., returns 0)
* <EOF> == ""
* [0-7]{1,3} == the character represented by the code
* interpreted as an octal number.
* [^ntb0-7\n] == the same character. I.e., "*" == '*'
*/
#define is_octal_digit(c) (((c)>='0') && ((c)<='7'))
static char
eat_escape_code(void)
{
int c, coded_char;
c = input();
switch (c) {
case 0: /* i.e., EOF */
unput(c);
return(c);
case '\n':
return(0);
case 'n':
return('\n');
case 't':
return('\t');
case 'b':
return('\b');
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
coded_char = c - '0';
c = input();
if (!is_octal_digit(c)) {
unput(c);
return(coded_char);
}
coded_char = coded_char*8 + c-'0';
c = input();
if (!is_octal_digit(c)) {
unput(c);
return(coded_char);
}
return(coded_char*8 + c-'0');
default:
return(c);
}
}
/*
* eat_string - this routine eats characters allowing escape codes via '\\'
* until a '"' is eaten. If no '"' is seen before a '\n' or
* the <EOF>, a parse_error is set & 0 is returned. Otherwise,
* the string represented by what has been eaten is returned.
* I.e., 'hello \n there"' would cause "hello \n there" to be
* returned. (thats not a <cr> in the first case, a <cr> in the
* second) The returned string is on the heap & must be freed
* eventually. This routine should be passed the line # that the
* string we are eating started on.
*/
static char *
eat_string(int starting_line)
{
int c;
char buffer[500];
char *ptr = buffer;
for (;;) {
/*
* Get the next input character, handling EOF:
*/
c = input();
if (!c) {
unput(c);
report_parse_error("unterminated string found beginning",
starting_line);
return(0);
}
/*
* Deal with special characters ('\\', '"', and '\n'):
*/
if (c=='\\') {
c = eat_escape_code();
if (!c)
continue;
} else if (c == '"') {
*ptr = 0;
return(string_Copy(buffer));
} else if (c == '\n') {
unput(c); /* fix line # reference to right line # */
report_parse_error("carriage return found in string", yylineno);
return(0);
}
/*
* Add the character c to the current string:
*/
*ptr = c;
ptr++;
/*
* If out of buffer space, do a recursive call then
* concatanate the result to the string read in so far to get the
* entire string and return that:
*/
if (ptr>buffer+sizeof(buffer)-20) {
string rest_of_string, result;
rest_of_string = eat_string(starting_line);
if (!rest_of_string)
return(0);
*ptr = 0;
result = string_Concat(buffer, rest_of_string);
free(rest_of_string);
return(result);
}
}
}
/*
* eat_show_line - internal routine for eat_show:
*
* This routine reads in a physical line of text allowing escape
* codes via '\\'. If the line ends with a newline, the newline is eaten.
* If the line ends with a EOF, the EOF is not eaten. The string
* represented by what has been eaten is returned. The returned string
* is on the heap & must be freed eventually. If test_for_endshow is
* true and the line read in starts off with "endshow" exactly
* (i.e., no escape codes) followed by any non-identifier-char, then
* instead of doing the above, we just eat the "endshow" & return 0.
*/
static char *
eat_show_line(int test_for_endshow)
{
int c;
int saw_escape_code = 0;
int starting_line = yylineno;
char buffer[200]; /* This must be large enough to hold "endshow" */
char *ptr = buffer;
while (yylineno == starting_line) {
c = input();
if (!c) {
unput(c);
*ptr = '\0';
return(string_Copy(buffer));
} else if (c == '\\') {
saw_escape_code = 1;
c = eat_escape_code();
if (!c)
continue;
}
*ptr = c;
ptr++;
if ((ptr==buffer+strlen("endshow")) && test_for_endshow)
if (!strncmp(buffer, "endshow", strlen("endshow"))
&& !saw_escape_code) {
c = input();
unput(c);
if (!is_identifier_char(c))
return(0);
}
if (ptr>buffer+sizeof(buffer)-2) {
string the_line;
string rest_of_line = eat_show_line(0);
*ptr = '\0';
the_line = string_Concat(buffer, rest_of_line);
free(rest_of_line);
return(the_line);
}
}
*ptr = '\0';
return(string_Copy(buffer));
}
/*
* eat_til_endshow - this routine eats characters allowing escape codes via
* '\\' up to a endshow\{nonalpha} found at the
* start of a line not counting leading whitespace.
* If <EOF> is seen before the terminator, a parse_error
* is set & 0 returned. Otherwise, the string represented
* by what has been eaten (escape codes replaced by what
* they stand for and leading spaces and tabs removed from
* each physical line) is returned. The returned string
* is on the heap & must be freed eventually. Note that
* to embed endshow in a message, endsho\w can be used.
* This routine should be passed the line # of the show
* command it is being used to process for use in error
* messages.
*/
static char *
eat_til_endshow(int start_line_no)
{
register int c;
string text_so_far = string_Copy("");
string next_line;
for (;;) {
/*
* Skip the spaces & tabs at the start of the current line:
*/
while ((c=input()), c==' ' || c=='\t') ;
unput(c);
/*
* Handle unterminated shows:
*/
if (!c) {
report_parse_error("unterminated show beginning", start_line_no);
free(text_so_far);
return(0);
}
/*
* Read in rest of the line (including the <cr> at end), allowing
* for escape codes and checking for "endshow{nonalpha}" at the
* start of the line. (Note: \<newline> is considered the
* end of a line here!)
*/
next_line = eat_show_line(1);
if (!next_line) /* i.e., is this the endshow line? */
return(text_so_far);
text_so_far = string_Concat2(text_so_far, next_line);
free(next_line);
}
}
/*
* handle_show - this routine is called after "show"\{nonalpha} is
* found to handle up to the endshow. The token # is
* returned.
*/
static int
handle_show(void)
{
int c;
int start_line_no = yylineno;
/*
* Eat up ' ' and '\t's after show. If the next character is a newline,
* eat it. This is so we don't get an extra newline when we call
* eat_til_endshow:
*/
while (c=input(), c==' ' || c=='\t') ;
if (c!='\n')
unput(c);
yylval.text = eat_til_endshow(start_line_no);
if (yylval.text)
return(SHOW);
else
return(ERROR);
}
/****************************************************************************/
/* */
/* The main lexer itself: */
/* */
/****************************************************************************/
/*
* yylex - performs as per. the yacc manual's requirements
*/
int yylex(void)
{
register int c, last_char;
register char *ptr;
int start_line_no;
int_dictionary_binding *binding;
char varname[MAX_IDENTIFIER_LENGTH+1];
for (;;) {
switch (c = input()) {
/*
* Skip whitespace:
*/
case ' ': case '\t': case '\n':
continue;
/*
* '#' comments out everything up to the and including
* the next <cr>:
*/
case '#':
while ( (c=input()) && (c!='\n') ) ;
if (!c)
unput(c);
continue;
/*
* Handle c-style comments. Note that "/[^*]" is not the start
* of any valid token.
*/
case '/':
start_line_no = yylineno;
/* verify that next character is a '*': */
if ((c=input()) != '*')
return(ERROR);
/* Scan until "*\/" or <EOF>: */
for (last_char=0; ; last_char=c) {
c = input();
if (c == '/' && (last_char=='*'))
break;
if (!c) {
unput(c);
report_parse_error("unterminated c style comment found beginning", start_line_no);
return(ERROR);
}
}
continue;
/*
* The following characters lex as themselves:
* '+', '|', '&', '(', ')', '.', ',' and <EOF>:
*/
case 0: case '+': case '|': case '&': case '(':
case ')': case '.': case ',':
return(c);
/*
* Handle "=[^~=]", "=~", and "==":
*/
case '=':
switch (c = input()) {
case '~':
return(REGEQ);
case '=':
return(EQ);
default:
unput(c);
return('=');
}
/*
* Handle "![^~=]", "!~", and "!=":
*/
case '!':
switch (c = input()) {
case '~':
return(REGNEQ);
case '=':
return(NEQ);
default:
unput(c);
return('!');
}
/*
* Handle identifiers and keywords:
*
* Note that the below set of characters is hard coded from
* is_identifier_char from parser.h.
*/
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y':
case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y':
case 'Z':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '_':
/*
* Read in the first MAX_IDENTIFIER_LENGTH characters of the
* identifier into varname null terminated. Eat
* the rest of the characters of the identifier:
*/
for (ptr = varname;;) {
if (ptr<varname+MAX_IDENTIFIER_LENGTH)
*(ptr++) = c;
c = input();
if (!is_identifier_char(c))
break;
}
unput(c);
*ptr = '\0';
/*
* Look up the identifier in the keyword dictionary.
* If its a match, return the keyword's #. In the case
* of show, call handle_show to do more processing.
* If not a match, treat as a variable name.
*/
binding = int_dictionary_Lookup(keyword_dict, varname);
if (!binding) {
yylval.text = string_Copy(varname);
return(VARNAME);
}
if (binding->value == SHOW)
return(handle_show());
else
return(binding->value);
/*
* Handle "${identifier}". Note that $ followed by a
* non-identifier character is not the start of any valid token.
*/
case '$':
c = input();
if (!is_identifier_char(c))
return(ERROR);
/*
* Read in the first MAX_IDENTIFIER_LENGTH characters of the
* identifier into varname null terminated. Eat
* the rest of the characters of the identifier:
*/
for (ptr = varname;;) {
if (ptr<varname+MAX_IDENTIFIER_LENGTH)
*(ptr++) = c;
c = input();
if (!is_identifier_char(c))
break;
}
unput(c);
*ptr = '\0';
yylval.text = string_Copy(varname);
return(VARREF);
/*
* Handle constant strings:
*/
case '"':
yylval.text = eat_string(yylineno);
if (yylval.text)
return(STRING);
else
return(ERROR);
/*
* All other characters do not start valid tokens:
*/
default:
return(ERROR);
}
}
}

59
zwgc/lexer.h Normal file
View File

@ -0,0 +1,59 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef lexer_MODULE
#define lexer_MODULE
#include <ctype.h>
/*
* is_identifier_char(c) - is c a character that could be part of
* an identifier?
*
* NOTE: this information is hardwired into yylex() in lexer.c!
*/
#define is_identifier_char(c) (isalnum(c) || (c)=='_')
/*
* The maximum # of significant letters in an identifier:
*
* Note: in order for all keywords to be recognized, this must be at least 20.
*/
#define MAX_IDENTIFIER_LENGTH 128
/*
* yylineno - this holds the current line # we are on. Updated automatically
* by yylex.
*/
extern int yylineno;
/*
* lex_open - this routine [re]initializes the lexer & prepares it to lex
* a file. Resets current line # to 1.
*/
extern void lex_open(FILE *);
/*
* yylex - performs as per. the yacc manual's requirements
*/
extern int yylex(void);
#endif

730
zwgc/main.c Normal file
View File

@ -0,0 +1,730 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#ifdef HAVE_ARES
#include <ares.h>
#endif
#if (!defined(lint) && !defined(SABER))
static const char rcsid_main_c[] = "$Id$";
#endif
#include <netdb.h>
#include <arpa/nameser.h>
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
#include <arpa/nameser_compat.h>
#endif
#include <sys/socket.h>
#include <sys/resource.h>
#include <locale.h>
#include <zephyr/mit-copyright.h>
#include <zephyr/zephyr.h>
#include "new_memory.h"
#include "zwgc.h"
#include "parser.h"
#include "node.h"
#include "exec.h"
#include "zephyr.h"
#include "notice.h"
#include "subscriptions.h"
#include "file.h"
#include "mux.h"
#include "port.h"
#include "variables.h"
#include "main.h"
#ifdef CMU_ZCTL_PUNT
#include "int_dictionary.h"
#endif
#ifdef CMU_ZWGCPLUS
#include "plus.h"
int zwgcplus = 1;
#endif
void notice_handler(ZNotice_t *);
static void process_notice(ZNotice_t *, char *);
static void setup_signals(int);
static void detach(void);
static void signal_exit(int);
#ifdef HAVE_ARES
static void notice_callback(void *, int, int, char *, char *);
#endif
/*
* Global zwgc-wide variables:
*/
#ifdef DEBUG
int zwgc_debug = 0;
#endif
static char *zwgc_version_string = "1.0";
/*
* description_filename_override - <<<>>>
*/
static char *description_filename_override = NULL;
/*
* progname - <<<>>> export!
*/
char *progname = NULL;
/*
* subscriptions_filename_override - <<<>>> export!
*/
char *subscriptions_filename_override = NULL;
/*
* location_override - <<<>>> export!
*/
char *location_override = NULL;
#ifdef HAVE_ARES
/*
* achannel - <<<>>> export!
*/
ares_channel achannel;
#endif
/****************************************************************************/
/* */
/* Code to deal with reading in the description file: */
/* */
/****************************************************************************/
/*
* program - this holds a pointer to the node representation of the
* description file once it has been read in.
*/
static struct _Node *program = NULL;
/*
* <<<>>>
*/
static void
fake_startup_packet(void)
{
ZNotice_t *notice = (ZNotice_t *)malloc(sizeof(ZNotice_t));
struct timezone tz;
char msgbuf[BUFSIZ];
extern void Z_gettimeofday(struct _ZTimeval *, struct timezone *);
var_set_variable("version", zwgc_version_string);
(void) memset(notice, 0, sizeof(ZNotice_t));
notice->z_version = "";
notice->z_class = "WG_CTL_CLASS";
notice->z_class_inst = "WG_CTL_USER<<<>>>";
notice->z_opcode = "WG_STARTUP";
notice->z_default_format = "Zwgc mark II version $version now running...\n";
notice->z_recipient = "";
notice->z_sender = "ZWGC";
Z_gettimeofday(&notice->z_time, &tz);
notice->z_port = 0;
notice->z_kind = ACKED;
notice->z_auth = ZAUTH_YES;
notice->z_charset = ZCHARSET_UNKNOWN;
sprintf(msgbuf,"Zwgc mark II version %s now running...",
zwgc_version_string);
notice->z_message = msgbuf;
notice->z_message_len = strlen(notice->z_message)+1;
#ifdef CMU_ZWGCPLUS
list_add_notice(notice);
set_notice_fake(notice, 1);
#endif
process_notice(notice, NULL);
#ifdef CMU_ZWGCPLUS
list_del_notice(notice);
#else
free(notice);
#endif
}
static void
read_in_description_file(void)
{
FILE *input_file;
char defdesc[128];
/* var_clear_all_variables(); <<<>>> */
sprintf(defdesc, "%s/zephyr/%s", DATADIR, DEFDESC);
input_file = locate_file(description_filename_override, USRDESC, defdesc);
if (input_file)
program = parse_file(input_file);
else
program = NULL;
fake_startup_packet();
}
/****************************************************************************/
/* */
/* Code to deal with argument parsing & overall control: */
/* */
/****************************************************************************/
/*
* void usage()
* Effects: Prints out an usage message on stderr then exits the
* program with error code 1.
*/
void
usage(void)
{
#ifdef DEBUG
fprintf(stderr, "\
zwgc: usage: zwgc [-debug] [-f <filename>] [-subfile <filename>]\n\
[-ttymode] [-nofork] [-reenter] [-loc text]\n\
[-default <driver>] {-disable <driver>}*\n\
[output driver options]\n");
#else
fprintf(stderr, "\
zwgc: usage: zwgc [-f <filename>] [-subfile <filename>]\n\
[-ttymode] [-nofork] [-reenter] [-loc text]\n\
[-default <driver>] {-disable <driver>}*\n\
[output driver options]\n");
#endif
exit(1);
}
/*
* <<<>>>
*/
static void
run_initprogs(void)
{
/*
* This code stolen from old zwgc: yuck. Clean up & fix. <<<>>>
* Should this fork instead of just systeming?
*/
int status;
char *iprogname = ZGetVariable("initprogs");
if (!iprogname)
return;
status = system(iprogname);
if (status == 127) {
perror("zwgc initprog exec");
fprintf(stderr,"zwgc initprog of <%s> failed: no shell.\n",
iprogname);
} else if (status!=-1 && status>>8) {
perror("zwgc initprog exec");
fprintf(stderr,"zwgc initprog of <%s> failed with status [%d].\n",
iprogname, status>>8);
}
}
/*
* main -- the program entry point. Does parsing & top level control.
*/
int
main(int argc, char **argv)
{
char **new;
register char **current;
int dofork = 1;
#ifdef HAVE_ARES
int status;
#endif
setlocale(LC_ALL, "");
progname = argv[0];
/*
* Process "-f <filename>", "-subfile <filename>", "-nofork",
* "-reenter" (which is ignored) and (if DEBUG) "-debug"
* arguments, removing then from argc, argv:
*/
for (new=current=argv+1; *current; current++) {
if (string_Eq(*current, "-debug")) {
argc--;
#ifdef DEBUG
zwgc_debug = 1;
#endif
} else if (string_Eq(*current, "-f")) {
argc -= 2; current++;
if (!*current)
usage();
description_filename_override = *current;
} else if (string_Eq(*current, "-subfile")) {
argc -= 2; current++;
if (!*current)
usage();
subscriptions_filename_override = *current;
} else if (string_Eq(*current, "-nofork")) {
argc--;
dofork = 0;
} else if (string_Eq(*current, "-reenter")) {
argc--; /* just throw it away */
} else if (string_Eq(*current, "-loc")) {
argc -= 2; current++;
if (!*current)
usage();
location_override = *current;
} else
*(new)++ = *current;
}
*new = *current;
#ifdef HAVE_ARES
/*
* Initialize resolver library
*/
status = ares_init(&achannel);
if (status != ARES_SUCCESS) {
fprintf(stderr, "Couldn't initialize resolver: %s\n",
ares_strerror(status));
return(1);
}
#endif
/*
* Initialize various subsystems in proper order:
*/
dprintf("Initializing subsystems...\n"); /*<<<>>>*/
#ifdef CMU_ZWGCPLUS
init_noticelist();
#endif
mux_init();
var_clear_all_variables(); /* <<<>>> */
init_ports(); /* <<<>>> */
dprintf("Initializing standard ports...\n");
init_standard_ports(&argc, argv);
if (argc>1)
usage();
dprintf("Initializing zephyr...\n");
setup_signals(dofork);
zephyr_init(notice_handler);
if (dofork)
detach();
/*
* Run the initprogs program(s) now that we are all set to deal:
*/
dprintf("Running initprogs program...\n");
run_initprogs();
dprintf("Test Zwgc parser.\n\n");
read_in_description_file();
dprintf("Entering main loop\n");
mux_loop();
dprintf("Returning from main loop\n");
finalize_zephyr();
return(0);
}
/****************************************************************************/
/* */
/* : */
/* */
/****************************************************************************/
#define USER_SUPPRESS "SUPPRESS"
#define USER_UNSUPPRESS "UNSUPPRESS"
#ifdef CMU_ZCTL_PUNT
#define USER_LIST_SUPPRESSED "LIST-SUPPRESSED"
#define PUNT_INC 1024
extern int_dictionary puntable_addresses_dict;
ZNotice_t punt_reply;
static void
create_punt_reply(int_dictionary_binding *punt_ent)
{
int key_len = strlen(punt_ent->key);
char *tmp;
if (!punt_reply.z_message) {
punt_reply.z_message = (char *)malloc(PUNT_INC);
punt_reply.z_message[0] = 0;
}
if ((punt_reply.z_message_len + key_len + 1) / PUNT_INC >
(punt_reply.z_message_len + PUNT_INC - 1) / PUNT_INC) {
char *new_message = (char *)malloc((punt_reply.z_message_len
/ PUNT_INC + 1) * PUNT_INC);
strcpy(new_message, punt_reply.z_message);
free(punt_reply.z_message);
punt_reply.z_message = new_message;
}
tmp = punt_reply.z_message + strlen(punt_reply.z_message);
strcat (punt_reply.z_message, punt_ent->key);
strcat (punt_reply.z_message, "\n");
punt_reply.z_message_len += key_len + 1;
while (*tmp != '\001') tmp++;
*tmp = ',';
while (*tmp != '\001') tmp++;
*tmp = ',';
}
#endif /* CMU_ZCTL_PUNT */
void
notice_handler(ZNotice_t *notice)
{
#ifndef HAVE_ARES
int ret;
char node[NS_MAXDNAME];
#endif
#if defined(CMU_ZWGCPLUS)
list_add_notice(notice);
#endif
#ifdef HAVE_ARES
ares_getnameinfo(achannel,
(const struct sockaddr *)&(notice->z_sender_sockaddr),
notice->z_sender_sockaddr.sa.sa_family == AF_INET ?
sizeof(struct sockaddr_in) :
notice->z_sender_sockaddr.sa.sa_family == AF_INET6 ?
sizeof(struct sockaddr_in6) :
sizeof(notice->z_sender_sockaddr), ARES_NI_LOOKUPHOST,
notice_callback, notice);
#else
ret = getnameinfo((const struct sockaddr *)&(notice->z_sender_sockaddr),
notice->z_sender_sockaddr.sa.sa_family == AF_INET ?
sizeof(struct sockaddr_in) :
notice->z_sender_sockaddr.sa.sa_family == AF_INET6 ?
sizeof(struct sockaddr_in6) :
sizeof(notice->z_sender_sockaddr),
node, sizeof(node), NULL, 0, 0);
if (ret != 0)
strcpy(node, "?");
process_notice(notice, node);
#ifdef CMU_ZWGCPLUS
/* Let list_del_notice clean up for us. */
#else
ZFreeNotice(notice);
free(notice);
#endif
#endif
}
#ifdef HAVE_ARES
/*
static void
notice_callback(void *arg,
int status,
int timeouts,
struct hostent *fromhost)
*/
static void
notice_callback(void *arg,
int status,
int timeouts,
char *node,
char *service)
{
ZNotice_t *notice = (ZNotice_t *) arg;
#ifdef CMU_ZWGCPLUS
plus_set_hname(notice, node);
#endif
process_notice(notice, node);
#ifdef CMU_ZWGCPLUS
list_del_notice(notice);
#else
ZFreeNotice(notice);
free(notice);
#endif
}
#endif
static void
process_notice(ZNotice_t *notice,
char *hostname)
{
char *control_opcode;
dprintf("Got a message\n");
control_opcode = decode_notice(notice, hostname);
if (control_opcode) {
#ifdef DEBUG
printf("got control opcode <%s>.\n", control_opcode);
#endif
if (!strcasecmp(control_opcode, USER_REREAD)) {
read_in_description_file();
} else if (!strcasecmp(control_opcode, USER_SHUTDOWN))
zwgc_shutdown();
else if (!strcasecmp(control_opcode, USER_STARTUP)) {
#ifdef DEBUG_MEMORY
report_memory_usage(); /* <<<>>> */
#endif
zwgc_startup();
} else if (!strcasecmp(control_opcode, USER_SUPPRESS)) {
string class = get_field(notice->z_message,
notice->z_message_len, 1);
string instance = get_field(notice->z_message,
notice->z_message_len, 2);
string recipient = get_field(notice->z_message,
notice->z_message_len, 3);
punt(class, instance, recipient);
free(class);
free(instance);
free(recipient);
} else if (!strcasecmp(control_opcode, USER_UNSUPPRESS)) {
string class = get_field(notice->z_message,
notice->z_message_len, 1);
string instance = get_field(notice->z_message,
notice->z_message_len, 2);
string recipient = get_field(notice->z_message,
notice->z_message_len, 3);
unpunt(class, instance, recipient);
free(class);
free(instance);
free(recipient);
#ifdef CMU_ZCTL_PUNT
} else if (!strcasecmp(control_opcode, USER_LIST_SUPPRESSED)) {
struct sockaddr_in old, to;
int retval;
if (!notice->z_port) {
printf("zwgc: can't reply to LIST-SUPPRESSED request\n");
return;
}
memset((char *) &punt_reply, 0, sizeof(ZNotice_t));
punt_reply.z_kind = CLIENTACK;
punt_reply.z_class = WG_CTL_CLASS;
punt_reply.z_class_inst = "WG_REPLY";
punt_reply.z_recipient = "zctl?";
punt_reply.z_sender = "Zwgc";
punt_reply.z_default_format = "";
punt_reply.z_opcode = USER_LIST_SUPPRESSED;
punt_reply.z_port = notice->z_port;
punt_reply.z_message = NULL;
punt_reply.z_message_len = 0;
if (puntable_addresses_dict) {
int_dictionary_Enumerate(puntable_addresses_dict,
create_punt_reply);
}
old = ZGetDestAddr();
to = old;
to.sin_port = notice->z_port;
if ((retval = ZSetDestAddr(&to)) != ZERR_NONE) {
com_err("zwgc",retval,"while setting destination address");
exit(1);
}
ZSendNotice(&punt_reply, ZNOAUTH);
if ((retval = ZSetDestAddr(&old)) != ZERR_NONE) {
com_err("zwgc",retval,"while resetting destination address");
exit(1);
}
if (punt_reply.z_message) {
free(punt_reply.z_message);
punt_reply.z_message = NULL;
}
#endif
} else if (!strcasecmp(control_opcode, USER_EXIT)) {
signal_exit(0);
} else
printf("zwgc: unknown control opcode %s.\n", control_opcode);
goto cleanup;
}
if (!zwgc_active) {
#ifdef DEBUG
if (zwgc_debug)
printf("NON-ACTIVE: PUNTED <%s>!!!!\n", notice->z_class_inst);
#endif
goto cleanup;
}
if (puntable_address_p(notice->z_class,
notice->z_class_inst,
notice->z_recipient)) {
#ifdef DEBUG
if (zwgc_debug)
printf("PUNTED <%s>!!!!\n", notice->z_class_inst);
#endif
goto cleanup;
}
exec_process_packet(program, notice);
cleanup:
return;
}
#ifdef CMU_ZWGCPLUS
void
reprocess_notice(ZNotice_t *notice, char *hostname)
{
list_add_notice(notice);
process_notice(notice, hostname);
list_del_notice(notice);
}
#endif
/***************************************************************************/
/*
*
*/
static void
signal_exit(int ignored)
{
mux_end_loop_p = 1;
}
/* clean up ALL the waiting children, in case we get hit with
multiple SIGCHLD's at once, and don't process in time. */
static RETSIGTYPE
signal_child(int ignored)
{
#ifdef HAVE_WAITPID
int status;
#else
union wait status;
#endif
int pid, old_errno = errno;
do {
#ifdef HAVE_WAITPID
pid = waitpid(-1, &status, WNOHANG);
#else
pid = wait3(&status, WNOHANG, (struct rusage *)0);
#endif
} while (pid != 0 && pid != -1);
errno = old_errno;
}
/* rewrite the wgfile in case it has gone away */
static RETSIGTYPE
signal_usr1(int ignored)
{
write_wgfile();
}
static void
setup_signals(int dofork)
{
#ifdef _POSIX_VERSION
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (dofork) {
sa.sa_handler = SIG_IGN;
sigaction(SIGINT, &sa, (struct sigaction *)0);
sigaction(SIGTSTP, &sa, (struct sigaction *)0);
sigaction(SIGQUIT, &sa, (struct sigaction *)0);
sigaction(SIGTTOU, &sa, (struct sigaction *)0);
} else {
/* clean up on SIGINT; exiting on logout is the user's problem, now. */
sa.sa_handler = signal_exit;
sigaction(SIGINT, &sa, (struct sigaction *)0);
}
/* behavior never changes */
sa.sa_handler = signal_exit;
sigaction(SIGTERM, &sa, (struct sigaction *)0);
sigaction(SIGHUP, &sa, (struct sigaction *)0);
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, (struct sigaction *)0);
sa.sa_handler = signal_child;
sigaction(SIGCHLD, &sa, (struct sigaction *)0);
sa.sa_handler = signal_usr1;
sigaction(SIGUSR1, &sa, (struct sigaction *)0);
#else /* !POSIX */
if (dofork) {
/* Ignore keyboard signals if forking. Bad things will happen. */
signal(SIGINT, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
} else {
/* clean up on SIGINT; exiting on logout is the user's problem, now. */
signal(SIGINT, signal_exit);
}
/* behavior never changes */
signal(SIGTERM, signal_exit);
signal(SIGHUP, signal_exit);
signal(SIGCHLD, signal_child);
signal(SIGPIPE, SIG_IGN); /* so that Xlib gets an error */
signal(SIGUSR1, signal_usr1);
#endif
}
/* detach() taken from old zwgc, with lots of stuff ripped out */
static void
detach(void)
{
/* detach from terminal and fork. */
register int i;
/* Attempt to join the process group of the session leader. This
* will get us a HUP if the session leader is in the foreground at
* logout time (which is often the case) or if the shell is running
* under telnetd or xterm (both of which HUP the process group of
* their child process). If we have getsid(), that's the best way
* of finding the session leader; otherwise use the process group of
* the parent process, which is a good guess. */
#if defined(HAVE_GETSID)
setpgid(0, getsid(0));
#elif defined(HAVE_GETPGID)
setpgid(0, getpgid(getppid()));
#elif !defined(GETPGRP_VOID)
setpgid(0, getpgrp(getppid()));
#endif
/* fork off and let parent exit... */
i = fork();
if (i) {
if (i < 0) {
perror("zwgc: cannot fork, aborting:");
exit(1);
}
exit(0);
}
}

54
zwgc/main.h Normal file
View File

@ -0,0 +1,54 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef main_MODULE
#define main_MODULE
#ifdef HAVE_ARES
#include <ares.h>
extern ares_channel achannel;
#endif
extern char *progname;
extern char *subscriptions_filename_override;
extern char *location_override;
/*
* void usage()
* Effects: Prints out a usage message on stderr then exits the
* program with error code 1.
*/
extern void usage(void);
#ifdef CMU_ZWGCPLUS
extern void reprocess_notice(ZNotice_t *notice, char *hostname);
#endif
/* USRDESC points to a file (relative to user's homedir) which has a user's
description file */
#define USRDESC ".zwgc.desc"
/* DEFDESC points to a file (relative to the data directory) which has the
* system default description file */
#ifndef DEFDESC
#define DEFDESC "zwgc.desc"
#endif
#endif

239
zwgc/mux.c Normal file
View File

@ -0,0 +1,239 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_mux_c[] = "$Id$";
#endif
/****************************************************************************/
/* */
/* Module containing code to wait on multiple file descriptors: */
/* */
/****************************************************************************/
#include <zephyr/zephyr.h>
#include "main.h"
#include "mux.h"
#include "error.h"
#include "zwgc.h"
#include "pointer.h"
#ifdef CMU_ZWGCPLUS
#include "plus.h"
#endif
#ifdef _AIX
#include <sys/select.h>
#endif
/*
* mux_end_loop_p - Setting this to true during a mux_loop causes the mux_loop
* to be exited.
*/
int mux_end_loop_p;
/*
* have_tty - is defined to be true if there is a controlling tty for this
* process. When we can no longer access the controlling tty,
* the process will die.
*/
static int have_tty = 0;
/*
* max_source - the maximum file descriptor that a handler was ever
* registered for:
*/
static int max_source = -1;
/*
* Which file descriptors we're waiting on for input & the accompanying
* input handlers & their arguments:
*/
static fd_set input_sources;
static void (*input_handler[MAX_SOURCES])(void *);
static pointer input_handler_arg[MAX_SOURCES];
static int check_tty(void);
/*
* void mux_init()
* Requires: mux_init has never been called before
* Effects: Initializes the mux module. Must be called before
* any other mux call.
*/
void
mux_init(void)
{
int i;
FD_ZERO(&input_sources);
for (i=0; i<MAX_SOURCES; i++)
input_handler[i] = NULL;
have_tty = check_tty();
}
/*
* void mux_add_input_source(int descriptor; void (*handler)(); pointer arg)
* Requires: 0<=descriptor<MAX_SOURCES, mux_init has been called
* Modifies: Removes the previous input handler if any for descriptor
* Effects: Registers handler as the input handler for file descriptor
* descriptor. When mux_loop() is running and input is
* available on descriptor, handler will be called with
* argument arg.
*/
void
mux_add_input_source(int descriptor,
void (*handler)(void *),
pointer arg)
{
#ifdef DEBUG
if(descriptor < 0 || descriptor >= MAX_SOURCES)
abort(); /* <<<>>> */
#endif
input_handler[descriptor] = handler;
input_handler_arg[descriptor] = arg;
FD_SET(descriptor, &input_sources);
if(descriptor > max_source)
max_source = descriptor;
}
/*
* void mux_loop()
* Requires: mux_init has been called.
* Effects: Loops until mux_end_loop_p becomes true. (Sets
* mux_end_loop_p false to start). Whenever input is
* available on an input source which has a registered
* handler (see mux_add_input_source), that handler is
* called with its argument. It is guaranteed that if
* input is available on a source, its respective input
* handler, if any, will eventually be called. No other
* ordering guarantees are made. When some signal handler
* or input handler eventually sets mux_end_loop_p to
* true, we return.
*/
void
mux_loop(void)
{
int i, nfds;
fd_set inputs, outputs;
struct timeval tv, *tvp;
mux_end_loop_p = 0;
for (;;) {
/*
* Exit if mux_end_loop_p has been set to true by a handler:
*/
if (mux_end_loop_p)
break;
tvp = NULL;
tv.tv_sec = 0;
if (have_tty) {
#ifdef CMU_ZWGCPLUS
tv.tv_sec = plus_timequeue_events();
if (tv.tv_sec > 10) tv.tv_sec = 10;
#else
tv.tv_sec = 10;
#endif
tv.tv_usec = 0;
#ifdef CMU_ZWGCPLUS
} else {
tv.tv_sec = plus_timequeue_events();
tv.tv_usec = 0;
#endif
}
if (tv.tv_sec)
tvp = &tv;
/*
* Do a select on all the file descriptors we care about to
* wait until at least one of them has input available:
*/
inputs = input_sources;
FD_ZERO(&outputs);
#ifdef HAVE_ARES
nfds = ares_fds(achannel, &inputs, &outputs);
if (nfds < max_source + 1)
nfds = max_source + 1;
tvp = ares_timeout(achannel, tvp, &tv);
#else
nfds = max_source + 1;
#endif
i = select(nfds, &inputs, &outputs, NULL, tvp);
if (i == -1) {
if (errno == EINTR)
continue; /* on a signal restart checking mux_loop_end_p */
else
FATAL_TRAP( errno, "while selecting" );
}
else if (i == 0) {
if (have_tty && !check_tty()) {
mux_end_loop_p = 1;
continue;
}
}
#ifdef HAVE_ARES
ares_process(achannel, &inputs, &outputs);
#endif
/*
* Call all input handlers whose corresponding file descriptors have
* input:
*/
for(i=0; i<=max_source; i++)
if (FD_ISSET(i, &inputs) && input_handler[i]) {
#ifdef DEBUG
if (zwgc_debug)
fprintf(stderr,
"mux_loop...activity on fd %d, calling %lx(%lx)\n",
i, (unsigned long)input_handler[i],
(unsigned long)input_handler_arg[i]);
#endif
input_handler[i](input_handler_arg[i]);
}
}
}
static int
check_tty(void)
{
register int result;
int pgrp;
int tty = open("/dev/tty", O_RDONLY|O_NDELAY);
if (tty < 0) return 0;
#if defined(_POSIX_VERSION)
result = ( ((pgrp = tcgetpgrp(tty)) < 0) ? 0 : 1 );
#else
result = ( (ioctl(tty, TIOCGPGRP, &pgrp) < 0) ? 0 : 1 );
#endif
close(tty);
return(result);
}

72
zwgc/mux.h Normal file
View File

@ -0,0 +1,72 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef mux_MODULE
#define mux_MODULE
/*
* MAX_SOURCES - the greatest file descriptor # that can be waited on minus one
* This can not exceed FD_SETSIZE from <sys/types.h>.
*/
#define MAX_SOURCES 32
/*
* mux_end_loop_p - Setting this to true during a mux_loop causes the mux_loop
* to be exited.
*/
extern int mux_end_loop_p;
/*
* void mux_init()
* Requires: mux_init has never been called before
* Effects: Initializes the mux module. Must be called before
* any other mux call.
*/
extern void mux_init(void);
/*
* void mux_add_input_source(int descriptior; void (*handler)(); void *arg)
* Requires: 0<=descriptor<MAX_SOURCES, mux_init has been called
* Modifies: Removes the previous input handler if any for descriptor
* Effects: Registers handler as the input handler for file descriptor
* descriptor. When mux_loop() is running and input is
* available on descriptor, handler will be called with
* argument arg.
*/
extern void mux_add_input_source(int, void (*)(void *), void *);
/*
* void mux_loop()
* Requires: mux_init has been called.
* Effects: Loops until mux_end_loop_p becomes true. (Sets
* mux_end_loop_p false to start). Whenever input is
* available on an input source which has a registered
* handler (see mux_add_input_source), that handler is
* called with its argument. It is guarenteed that if
* input is available on a source, its respective input
* handler, if any, will eventually be called. No other
* ordering guarentees are made. When some signal handler
* or input handler eventually sets mux_end_loop_p to
* true, we return.
*/
extern void mux_loop(void);
#endif

244
zwgc/new_memory.c Normal file
View File

@ -0,0 +1,244 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_new_memory_c[] = "$Id$";
#endif
#if !defined(SABER) && (defined(DEBUG) || defined(MEMORY_DEBUG))
/*
* memory - module wrapping debugging code around normal malloc/free/etc.
* routines.
*
* Overview:
*
* ...
*/
#define memory__PROVIDER
#include "new_memory.h"
/*
*
*/
#ifdef DEBUG
#define assert(x) if (!(x)) abort()
#else
#define assert(x)
#endif
/*
*
*/
#ifdef DEBUG_MEMORY
extern void record_request();
char *current_module = 0;
int current_line = -1;
#endif
/*
* string string_CreateFromData(char *data, int length):
* Requires: data[0], data[1], ..., data[length-1] != 0
* Effects: Takes the first length characters at data and
* creates a string containing them. The returned string
* is on the heap & must be freed eventually.
* I.e., if passed "foobar" and 3, it would return
* string_Copy("foo").
*/
void *memory__malloc(size)
unsigned size;
{
char *result;
result = malloc(size + memory__size_of_header);
if (!result)
abort(); /* <<<>>> */
#ifdef DEBUG_MEMORY
((memory_block_header *)result)->size = size;
((memory_block_header *)result)->creating_module = current_module;
((memory_block_header *)result)->line_number_in_creating_module =
current_line;
((memory_block_header *)result)->check_field = CHECK_FIELD_VALUE;
result += memory__size_of_header;
record_request(current_module, current_line, 1, size);
#endif
return(result);
}
void *memory__realloc(aptr, size)
void *aptr;
unsigned size;
{
char *result, *ptr = aptr;
assert(ptr);
#ifdef DEBUG_MEMORY
if (!memory__on_heap_p(ptr)) {
printf("realloced non-memory block in %s on line %d!\n",
current_module, current_line);
fflush(stdout);
return(realloc(ptr, size));
}
#endif
result = realloc(ptr-memory__size_of_header, size+memory__size_of_header);
if (!result)
abort(); /* <<<>>> */
return(result+memory__size_of_header);
}
void *memory__calloc(nelem, elsize)
unsigned nelem;
unsigned elsize;
{
char *result;
#ifdef DEBUG_MEMORY
printf("in calloc\n"); fflush(stdout);
#endif
abort();
#ifdef FRED
result = calloc(nelem, elsize);
if (!result)
abort();
record_request(1);
#endif
return(result);
}
void memory__free(aptr)
void *aptr;
{
char *ptr = aptr;
assert(ptr);
#ifdef DEBUG_MEMORY
if (!memory__on_heap_p(ptr)) {
printf("freed non-memory block in %s on line %d!\n", current_module,
current_line);
fflush(stdout);
(void)free(ptr);
return;
}
record_request(memory__get_header(ptr)->creating_module,
memory__get_header(ptr)->line_number_in_creating_module,
-1,
memory__get_header(ptr)->size);
#endif
(void)free(ptr-memory__size_of_header);
}
#ifdef DEBUG_MEMORY
#include "int_dictionary.h"
static int request_off = 0;
static int_dictionary requests = 0;
static int outstanding_requests = 0;
static int outstanding_memory = 0;
void record_request(module, line_number, dir, size)
char *module;
int line_number;
int dir;
unsigned int size;
{
int_dictionary_binding *binding;
int already_exists;
#ifdef LINE
char buffer[20];
#endif
if (request_off)
return;
request_off = 1;
if (!requests)
requests = int_dictionary_Create(101);
#ifdef LINE
module = string_Concat(module, ":");
sprintf(buffer, "%d", line_number);
module = string_Concat2(module, buffer);
#endif
binding = int_dictionary_Define(requests, module, &already_exists);
if (!already_exists)
binding->value = 0;
#ifdef LINE
free(module);
#endif
binding->value += dir;
outstanding_requests += dir;
outstanding_memory += size*dir;
request_off = 0;
}
void proc(binding)
int_dictionary_binding *binding;
{
if (binding->value)
printf(" %-30s %6d blocks allocated\n", binding->key, binding->value);
}
void report_memory_usage()
{
printf("\n# of blocks on the heap = %d\n", outstanding_requests);
printf("Total heap space in use: %d bytes\n", outstanding_memory);
printf("\nHeap Allocations by module:\n");
int_dictionary_Enumerate(requests, proc);
printf("\n");
fflush(stdout);
}
void set_module(file, line)
char *file;
int line;
{
if (request_off)
return;
if (!strcmp(file, "new_string.c"))
return;
if (!strcmp(file, "string_dictionary_aux.c"))
return;
current_line = line;
current_module = file;
}
#endif
#endif /* SABER */

84
zwgc/new_memory.h Normal file
View File

@ -0,0 +1,84 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
/* This entire module goes out the window in saber */
#if !defined(SABER) && (defined(DEBUG) || defined(DEBUG_MEMORY))
#ifndef memory_MODULE
#define memory_MODULE
extern void *memory__malloc(unsigned); /* PRIVATE */
extern void *memory__realloc(void *, unsigned); /* PRIVATE */
extern void *memory__calloc(unsigned, unsigned); /* PRIVATE */
extern void memory__free(void *); /* PRIVATE */
#ifdef DEBUG_MEMORY
#define CHECK_FIELD_VALUE 0xe5e7e3e9
typedef struct _memory_block_header {
unsigned size;
char *creating_module;
int line_number_in_creating_module;
unsigned int check_field;
} memory_block_header;
#define memory__size_of_header (sizeof(struct _memory_block_header))
#define memory__get_header(block) \
((struct _memory_block_header *)((block)-memory__size_of_header))
#define memory__on_heap_p(block) \
(memory__get_header(block)->check_field==CHECK_FIELD_VALUE)
#else
#define memory__size_of_header 0
#define memory__on_heap_p(block) 1
#endif
/*
* int string_Length(string s):
* Effects: Returns the number of non-null characters in s.
*/
#ifndef memory__PROVIDER
#ifdef DEBUG_MEMORY
extern char *current_module;
extern void set_module();
#define malloc(size) (set_module(__FILE__,__LINE__),\
memory__malloc(size))
#define realloc(ptr, size) (set_module(__FILE__,__LINE__),\
memory__realloc((char *) ptr, size))
#define calloc(nelem, elsize) (set_module(__FILE__,__LINE__),\
memory__calloc(nelem, elsize))
#define free(ptr) (set_module(__FILE__,__LINE__),\
memory__free((char *) ptr))
#else
#define malloc(size) memory__malloc(size)
#define realloc(ptr, size) memory__realloc((char *) ptr, size)
#define calloc(nelem, elsize) memory__calloc(nelem, elsize)
#define free(ptr) memory__free((char *) ptr)
#endif /* DEBUG_MEMORY */
#endif /* memory__PROVIDER */
#endif /* memory_MODULE */
#endif /* SABER */

193
zwgc/new_string.c Normal file
View File

@ -0,0 +1,193 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#include "new_string.h"
#if (!defined(lint) && !defined(SABER))
static const char rcsid_new_string_c[] = "$Id$";
#endif
/*
* string - a module providing operations on C strings. (i.e., char *'s)
*
* Overview:
*
* A string is a standard C string. I.e., a char pointer to a
* null-terminated sequence of characters. 0 is NOT considered a valid
* string! Various operations are available. See the string_spec file
* for details.
*
* Note: This module assumes that malloc NEVER returns 0 for reasonable
* requests. It is the users responsibility to either ensure that
* this happens or supply a version of malloc with error
* handling.
*
* Some strings are mutable.
*/
#ifdef DEBUG
#define assert(x) if (!(x)) abort()
#else
#define assert(x)
#endif
#include "new_memory.h"
/*
* string string_CreateFromData(char *data, int length):
* Requires: data[0], data[1], ..., data[length-1] != 0
* Effects: Takes the first length characters at data and
* creates a string containing them. The returned string
* is on the heap & must be freed eventually.
* I.e., if passed "foobar" and 3, it would return
* string_Copy("foo").
*/
string string__CreateFromData(char *data, int length)
{
string result;
assert(length>=0);
result = (string)malloc(length+1);
assert(result);
(void) memcpy(result, data, length);
result[length] = 0;
return(result);
}
/*
* string string_Copy(string s):
* Effects: Returns a copy of s on the heap. The copy must be
* freed eventually.
*/
string
string__Copy(string s)
{
int length;
string result;
assert(s);
length = string_Length(s)+1;
result = (string)malloc(length);
assert(result);
(void) memcpy(result, s, length);
return(result);
}
/*
* string string_Concat(string a, b):
* Effects: Returns a string equal to a concatenated to b.
* The returned string is on the heap and must be
* freed eventually. I.e., given "abc" and "def",
* returns string_Copy("abcdef").
*/
string
string__Concat(string a,
string b)
{
string result;
int a_length, b_size, result_size;
a_length = string_Length(a);
b_size = string_Length(b)+1;
result_size = a_length+b_size;
result = (string)malloc(result_size);
assert(result);
(void) memcpy(result, a, a_length);
(void) memcpy(result+a_length, b, b_size);
return(result);
}
/*
* string string_Concat2(string a, b):
* Modifies: a
* Requires: a is on the heap, b does not point into a.
* Effects: Equivalent to:
* string temp;
* temp = string_Concat(a,b);
* free(a);
* return(temp);
* only faster. I.e., uses realloc instead of malloc+memcpy.
*/
string
string__Concat2(string a,
string b)
{
int a_length = string_Length(a);
int b_size = string_Length(b)+1;
#ifdef DEBUG_MEMORY
assert(memory__on_heap_p(a));
#endif
a = (string)realloc(a, a_length+b_size);
assert(a);
(void) memcpy(a+a_length, b, b_size);
return(a);
}
/*
* string string_Downcase(string s):
* Modifies: s
* Effects: Modifies s by changing every uppercase character in s
* to the corresponding lowercase character. Nothing else
* is changed. I.e., "FoObAr19." is changed to "foobar19.".
* S is returned as a convenience.
*/
string
string_Downcase(string s)
{
char *ptr;
for (ptr=s; *ptr; ptr++) {
if (isupper(*ptr))
*ptr = tolower(*ptr);
}
return(s);
}
/*
* string string_Upcase(string s):
* Modifies: s
* Effects: Modifies s by changing every lowercase character in s
* to the corresponding uppercase character. Nothing else
* is changed. I.e., "FoObAr19." is changed to "FOOBAR19.".
* S is returned as a convenience.
*/
string
string_Upcase(string s)
{
char *ptr;
for (ptr=s; *ptr; ptr++) {
if (islower(*ptr))
*ptr = toupper(*ptr);
}
return(s);
}

134
zwgc/new_string.h Normal file
View File

@ -0,0 +1,134 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#ifndef string_TYPE
#define string_TYPE
#include <string.h>
#include "new_memory.h"
typedef char *string;
/*
* int string_Length(string s):
* Effects: Returns the number of non-null characters in s.
*/
#define string_Length(s) strlen(s)
/*
* int string_Eq(string a, b):
* Effects: Returns true iff strings a & b are equal. I.e., have the
* same character contents.
*/
#define string_Eq(a,b) (!strcmp(a,b))
/*
* int string_Neq(string a, b):
* Effects: Returns true iff strings a & b are not equal.
*/
#define string_Neq(a,b) (strcmp(a,b))
/*
* string string_CreateFromData(char *data, int length):
* Requires: data[0], data[1], ..., data[length-1] != 0
* Effects: Takes the first length characters at data and
* creates a string containing them. The returned string
* is on the heap & must be freed eventually.
* I.e., if passed "foobar" and 3, it would return
* string_Copy("foo").
*/
extern string string__CreateFromData(char *, int);
#ifdef DEBUG_MEMORY
#define string_CreateFromData(data,length) (set_module(__FILE__,__LINE__),\
string__CreateFromData(data,length))
#else
#define string_CreateFromData(data,length) string__CreateFromData(data,length)
#endif
/*
* string string_Copy(string s):
* Effects: Returns a copy of s on the heap. The copy must be
* freed eventually.
*/
extern string string__Copy(string);
#ifdef DEBUG_MEMORY
#define string_Copy(data) (set_module(__FILE__,__LINE__),\
string__Copy(data))
#else
#define string_Copy(data) string__Copy(data)
#endif
/*
* string string_Concat(string a, b):
* Effects: Returns a string equal to a concatenated to b.
* The returned string is on the heap and must be
* freed eventually. I.e., given "abc" and "def",
* returns string_Copy("abcdef").
*/
extern string string__Concat(string, string);
#ifdef DEBUG_MEMORY
#define string_Concat(a,b) (set_module(__FILE__,__LINE__),\
string__Concat(a,b))
#else
#define string_Concat(a,b) string__Concat(a,b)
#endif
/*
* string string_Concat2(string a, b):
* Modifies: a
* Requires: a is on the heap, b does not point into a.
* Effects: Equivalent to:
* string temp;
* temp = string_Concat(a,b);
* free(a);
* return(temp);
* only faster. I.e., uses realloc instead of malloc+bcopy.
*/
extern string string__Concat2(string, string);
#ifdef DEBUG_MEMORY
#define string_Concat2(a,b) (set_module(__FILE__,__LINE__),\
string__Concat2(a,b))
#else
#define string_Concat2(a,b) string__Concat2(a,b)
#endif
/*
* string string_Downcase(string s):
* Modifies: s
* Effects: Modifies s by changing every uppercase character in s
* to the corresponding lowercase character. Nothing else
* is changed. I.e., "FoObAr19." is changed to "foobar19.".
* S is returned as a convenience.
*/
extern string string_Downcase(string);
/*
* string string_Upcase(string s):
* Modifies: s
* Effects: Modifies s by changing every lowercase character in s
* to the corresponding uppercase character. Nothing else
* is changed. I.e., "FoObAr19." is changed to "FOOBAR19.".
* S is returned as a convenience.
*/
extern string string_Upcase(string);
#endif

331
zwgc/node.c Normal file
View File

@ -0,0 +1,331 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_node_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
#include "new_memory.h"
#include "node.h"
/****************************************************************************/
/* */
/* Internal node construction & destruction functions: */
/* */
/****************************************************************************/
/*
* NODE_BATCH_SIZE - the number of nodes to malloc at once to save overhead:
*/
#define NODE_BATCH_SIZE 100
/*
* The nodes we have malloced are kept in a linked list of bunches of
* NODE_BATCH_SIZE nodes. Nodes points to the first bunch on the list
* and current_bunch to the last. All nodes from the first one in the first
* bunch to the last_node_in_current_bunch_used'th one in the last bunch
* are in use. The others have not been used yet.
*/
static struct _bunch_of_nodes {
struct _bunch_of_nodes *next_bunch;
Node nodes[NODE_BATCH_SIZE];
} *nodes = NULL;
static struct _bunch_of_nodes *current_bunch = NULL;
static int last_node_in_current_bunch_used = -1;
/*
* Internal Routine:
*
* Node *node_create(int opcode)
* Effects: Creates a node with opcode opcode and returns a pointer
* to it. The next pointer of the returned node is NULL.
* If the opcode is STRING_CONSTANT_OPCODE the caller must
* ensure that the string_constant field points to a valid
* string on the heap when node_DestroyAllNodes is called.
*/
static Node *
node_create(int opcode)
{
Node *result;
if (!nodes) {
/*
* Handle special case where no nodes allocated yet:
*/
current_bunch = nodes = (struct _bunch_of_nodes *)
malloc(sizeof(struct _bunch_of_nodes));
nodes->next_bunch = NULL;
last_node_in_current_bunch_used = -1;
}
/*
* If all nodes allocated so far in use, allocate another
* bunch of NODE_BATCH_SIZE nodes:
*/
if (last_node_in_current_bunch_used == NODE_BATCH_SIZE-1) {
current_bunch->next_bunch = (struct _bunch_of_nodes *)
malloc(sizeof(struct _bunch_of_nodes));
current_bunch = current_bunch->next_bunch;
current_bunch->next_bunch = NULL;
last_node_in_current_bunch_used = -1;
}
/*
* Get next not already used node & ready it for use:
*/
last_node_in_current_bunch_used++;
result = &(current_bunch->nodes[last_node_in_current_bunch_used]);
result->opcode = opcode;
result->next = NULL;
return(result);
}
/*
*
*/
void
node_DestroyAllNodes(void)
{
struct _bunch_of_nodes *next_bunch;
int i, last_node_used_in_this_bunch;
while (nodes) {
next_bunch = nodes->next_bunch;
last_node_used_in_this_bunch = next_bunch ?
NODE_BATCH_SIZE-1 : last_node_in_current_bunch_used;
for (i=0; i<=last_node_used_in_this_bunch; i++) {
if (nodes->nodes[i].opcode==STRING_CONSTANT_OPCODE)
free(nodes->nodes[i].d.string_constant);
else if (nodes->nodes[i].opcode==VARREF_OPCODE)
free(nodes->nodes[i].d.string_constant);
else if (nodes->nodes[i].opcode==VARNAME_OPCODE)
free(nodes->nodes[i].d.string_constant);
}
free(nodes);
nodes = next_bunch;
}
current_bunch = nodes;
}
/****************************************************************************/
/* */
/* Node construction functions: */
/* */
/****************************************************************************/
Node *
node_create_string_constant(int opcode,
string text)
{
Node *n;
n = node_create(opcode);
n->d.string_constant = text;
return(n);
}
Node *
node_create_noary(int opcode)
{
Node *n;
n = node_create(opcode);
return(n);
}
Node *
node_create_unary(int opcode,
Node *arg)
{
Node *n;
n = node_create(opcode);
n->d.nodes.first = arg;
return(n);
}
Node *
node_create_binary(int opcode,
Node *first_arg,
Node *second_arg)
{
Node *n;
n = node_create(opcode);
n->d.nodes.first = first_arg;
n->d.nodes.second = second_arg;
return(n);
}
/****************************************************************************/
/* */
/* Node utility functions: */
/* */
/****************************************************************************/
/*
* Node *reverse_list_of_nodes(Node *list)
* Modifies: the nodes on the linked list list
* Effects: Reverses the linked list list and returns it.
* This is done by modifing the next pointers of the
* list elements to point to the previous node & returning
* the address of the (previously) last node.
*/
Node *
reverse_list_of_nodes(Node *list)
{
Node *next_node;
Node *head = NULL;
while (list) {
next_node = list->next;
/*
* Add the node list to the beginning of linked list head:
*/
list->next = head;
head = list;
list = next_node;
}
return(head);
}
/****************************************************************************/
/* */
/* Node display functions: */
/* */
/****************************************************************************/
#ifdef DEBUG
static void
print_stuff(Node *node,
string format_string)
{
char c;
for (c=(*(format_string++)); c; c=(*(format_string++))) {
if (c!='%') {
putchar(c);
continue;
}
c=(*(format_string++));
if (!c) {
format_string--;
continue;
}
if (c=='s')
printf("%s", node->d.string_constant);
else if (c=='1')
node_display(node->d.nodes.first);
else if (c=='2')
node_display(node->d.nodes.second);
else
putchar(c);
}
}
static string how_to_print[] = {
"\"%s\"", /* constant string */
"$%s", /* varref */
"%s", /* varname */
"!%1",
"( %1 + %2 )",
"( %1 and %2 )",
"( %1 or %2 )",
"( %1 == %2 )",
"( %1 != %2 )",
"( %1 =~ %2 )",
"( %1 !~ %2 )",
"buffer()",
"substitute(%1)",
"protect(%1)",
"verbatim(%1)",
"stylestrip(%1)",
"getenv(%1)",
"upcase(%1)",
"downcase(%1)",
"zvar(%1)",
"get(%1)",
"lany(%1, %2)",
"rany(%1, %2)",
"lbreak(%1, %2)",
"rbreak(%1, %2)",
"lspan(%1, %2)",
"rspan(%1, %2)",
"noop\n",
"set %1 = %2\n",
"fields %1\n",
"print %1\n",
"clearbuf\n",
"appendport %1 %2\n",
"execport %1 %2\n",
"inputport %1 %2\n",
"outputport %1 %2\n",
"put %1 %2\n",
"closeinput %1\n",
"closeoutput %1\n",
"closeport %1\n",
"exec %1 %2\n",
"%1endif\n",
"case %1\n%2endcase\n",
"while %1 do\n%2endwhile\n",
"break\n",
"exit\n",
"if %1 then\n%2",
"elseif %1 then\n%2",
"else\n%2",
"match %1\n%2",
"default\n%2" };
void node_display(Node *node)
{
int opcode = LAST_EXPR_OPCODE + 1;
for (; node; node=node->next) {
if (opcode<=LAST_EXPR_OPCODE)
printf(" ");
opcode = node->opcode;
if (opcode>=0 && opcode<NUMBER_OF_OPCODES)
print_stuff(node, how_to_print[opcode]);
else
printf("[opcode %d]", opcode);
}
}
#endif

126
zwgc/node.h Normal file
View File

@ -0,0 +1,126 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef node_MODULE
#define node_MODULE
#include "new_string.h"
#define STRING_CONSTANT_OPCODE 0
#define VARREF_OPCODE 1
#define VARNAME_OPCODE 2
#define NOT_OPCODE 3
#define PLUS_OPCODE 4
#define AND_OPCODE 5
#define OR_OPCODE 6
#define EQ_OPCODE 7
#define NEQ_OPCODE 8
#define REGEQ_OPCODE 9
#define REGNEQ_OPCODE 10
#define BUFFER_OPCODE 11
#define SUBSTITUTE_OPCODE 12
#define PROTECT_OPCODE 13
#define VERBATIM_OPCODE 14
#define STYLESTRIP_OPCODE 15
#define GETENV_OPCODE 16
#define UPCASE_OPCODE 17
#define DOWNCASE_OPCODE 18
#define ZVAR_OPCODE 19
#define GET_OPCODE 20
#define LANY_OPCODE 21
#define RANY_OPCODE 22
#define LBREAK_OPCODE 23
#define RBREAK_OPCODE 24
#define LSPAN_OPCODE 25
#define RSPAN_OPCODE 26
#define LAST_EXPR_OPCODE 26
#define NOOP_OPCODE 27
#define SET_OPCODE 28
#define FIELDS_OPCODE 29
#define PRINT_OPCODE 30
#define CLEARBUF_OPCODE 31
#define APPENDPORT_OPCODE 32
#define EXECPORT_OPCODE 33
#define INPUTPORT_OPCODE 34
#define OUTPUTPORT_OPCODE 35
#define PUT_OPCODE 36
#define CLOSEINPUT_OPCODE 37
#define CLOSEOUTPUT_OPCODE 38
#define CLOSEPORT_OPCODE 39
#define EXEC_OPCODE 40
#define IF_STMT_OPCODE 41
#define CASE_OPCODE 42
#define WHILE_OPCODE 43
#define BREAK_OPCODE 44
#define EXIT_OPCODE 45
#define IF_OPCODE 46
#define ELSEIF_OPCODE 47
#define ELSE_OPCODE 48
#define MATCHLIST_OPCODE 49
#define DEFAULT_OPCODE 50
#define NUMBER_OF_OPCODES 51
typedef struct _Node {
int opcode; /* Read-only */
struct _Node *next;
union {
string string_constant;
struct {
struct _Node *first;
struct _Node *second;
} nodes;
} d;
} Node;
/* Function externs */
extern void node_DestroyAllNodes(void);
extern Node *node_create_string_constant(int, string);
extern Node *node_create_noary(int);
extern Node *node_create_unary(int, Node *);
extern Node *node_create_binary(int, Node *, Node *);
/*
* Node *reverse_list_of_nodes(Node *list)
* Modifies: the nodes on the linked list list
* Effects: Reverses the linked list list and returns it.
* This is done by modifing the next pointers of the
* list elements to point to the previous node & returning
* the address of the (previously) last node.
*/
extern Node *reverse_list_of_nodes(Node *);
#ifdef DEBUG
extern void node_display(Node *);
#endif
#endif

351
zwgc/notice.c Normal file
View File

@ -0,0 +1,351 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_notice_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* Module containing code to extract a notice's fields: */
/* */
/****************************************************************************/
#include <zephyr/zephyr.h>
#include <arpa/inet.h>
#include "new_memory.h"
#include "error.h"
#include "variables.h"
#include "notice.h"
#ifdef CMU_ZWGCPLUS
#include <pwd.h>
#include "plus.h"
#endif
/*
* int count_nulls(char *data, int length)
* Requires: length>=0
* Effects: Returns the # of nulls in data[0]..data[length-1]
*/
int
count_nulls(char *data,
int length)
{
int count = 0;
for (; length; data++, length--)
if (!*data)
count++;
return(count);
}
/*
* string get_next_field(char **data_p, int *length_p)
* Requires: *length_p >= 0
* Modifies: *data_p, *length_p
* Effects: Treats (*data_p)[0], (*data_p)[1], ... (*data_p)[length-1]
* as a series of null-seperated fields. This function
* returns a copy of the first field on the heap. This
* string must eventually be freed. Also, *data_p is
* advanced and *length_p decreased so that another
* call to this procedure with the same arguments will
* return the second field. The next call will return
* the third field, etc. "" is returned if 0 fields
* remain. (this is the case when *length_p == 0)
*/
string
get_next_field(char **data_p,
int *length_p)
{
char *data = *data_p;
int length = *length_p;
char *ptr;
for (ptr=data; length; ptr++, length--)
if (!*ptr) {
*data_p = ptr+1;
*length_p = length-1;
return(string_Copy(data));
}
length = *length_p;
*data_p = ptr;
*length_p = 0;
return(string_CreateFromData(data, length));
}
/*
* string get_field(char *data, int length, int num)
* Requires: length>=0, num>0
* Effects: Treats data[0]..data[length-1] as a series of
* null-seperated fields. This function returns a copy of
* the num'th field (numbered from 1 in this case) on the
* heap. This string must eventually be freed. If there
* is no num'th field (because num<1 or num># of fields),
* "" is returned.
*/
string get_field(char *data,
int length,
int num)
{
/*
* While num>1 and there are fields left, skip a field & decrement num:
*/
while (length && num>1) {
if (!*data)
num--;
length--;
data++;
}
/*
* If any more fields left, the first field is the one we want.
* Otherwise, there is no such field as num -- return "".
*/
if (length)
return(get_next_field(&data, &length));
else
return(string_Copy(""));
}
/*
* string convert_nulls_to_newlines(data, length)
* Requires: length>=0, malloc never returns NULL
* Effects: Takes data[0]..data[length-1], converts all nulls to
* newlines ('\n') and returns the result as a null-terminated
* string on the heap. The returned string must eventually
* be freed.
*/
string
convert_nulls_to_newlines(char *data,
int length)
{
char *result, *ptr;
char c;
result = (char *) malloc(length+1);
result[length] = '\0';
for (ptr=result; length; data++, ptr++, length--)
*ptr = (c = *data) ? c : '\n';
return(result);
}
/*
* Internal Routine:
*
* string z_kind_to_ascii(ZNotice_Kind_t z_kind)
* Effects: Returns an ascii representation for z_kind.
* The string returned is on the heap and must be freed
* eventually.
*/
static string
z_kind_to_ascii(ZNotice_Kind_t z_kind)
{
string result;
switch (z_kind) {
case UNSAFE:
result = "unsafe";
break;
case UNACKED:
result = "unacked";
break;
case ACKED:
result = "acked";
break;
case HMACK:
result = "hmack";
break;
case HMCTL:
result = "hmctl";
break;
case SERVACK:
result = "servack";
break;
case SERVNAK:
result = "servnak";
break;
case CLIENTACK:
result = "clientack";
break;
case STAT:
result = "stat";
break;
default:
result = "<unknown kind>";
break;
}
return(string_Copy(result));
}
/*
* Internal Routine:
*
* string z_auth_to_ascii(int z_auth)
* Effects: Returns an ascii representation for z_auth.
* The string returned is on the heap and must be freed
* eventually.
*/
static string
z_auth_to_ascii(int z_auth)
{
string result;
switch (z_auth) {
case ZAUTH_FAILED:
result = "forged";
break;
case ZAUTH_NO:
result = "no";
break;
case ZAUTH_YES:
result = "yes";
break;
default:
result = "unknown";
break;
}
return(string_Copy(result));
}
/*
* char *decode_notice(ZNotice_t *notice)
* Modifies: various description language variables
* Effects:
*/
char *
decode_notice(ZNotice_t *notice,
char *hostname)
{
char *temp;
string when, notyear, year, date_string, time_string;
/*
* Convert useful notice fields to ascii and store away in
* description language variables for later use by the
* the user's program:
*/
var_set_variable("zephyr_version", notice->z_version);
var_set_variable("class", notice->z_class);
var_set_variable("instance", notice->z_class_inst);
var_set_variable("opcode", notice->z_opcode);
var_set_variable("default", notice->z_default_format);
var_set_variable("notice_charset", (char *)ZCharsetToString(notice->z_charset)); /*XXX const*/
var_set_variable("recipient",
(notice->z_recipient[0] ? notice->z_recipient : "*"));
var_set_variable("fullsender", notice->z_sender);
var_set_variable_to_number("port", (int)ntohs(notice->z_port));
var_set_variable_then_free_value("kind", z_kind_to_ascii(notice->z_kind));
var_set_variable_then_free_value("auth", z_auth_to_ascii(notice->z_auth));
#ifdef CMU_ZWGCPLUS
if ((temp=getSelectedText()) != 0)
var_set_variable("selection", temp);
var_set_variable("delete_window", "none");
var_set_variable("event_time", "none");
var_set_variable("event_name", "event");
#endif
/*
* Set $sender to the name of the notice sender except first strip off the
* realm name if it is the local realm:
*/
if ( (temp=strchr(notice->z_sender,'@')) && string_Eq(temp+1, ZGetRealm()) )
var_set_variable_then_free_value("sender",
string_CreateFromData(notice->z_sender,
temp-notice->z_sender));
else
var_set_variable("sender", notice->z_sender);
#ifdef CMU_ZWGCPLUS
if (get_full_names) {
struct passwd *pwnam = getpwnam(var_get_variable("sender"));
if (pwnam) {
temp = string_Copy(pwnam->pw_gecos);
var_set_variable_then_free_value("sendername", temp);
} else {
var_set_variable("sendername", "unknown");
}
}
#endif
/*
* Convert time & date notice was sent to ascii. The $time
* has the format "01:03:52" while $date has the format
* "Sun Sep 16 1973".
*/
{
/* the fields of struct timeval might not be the right type to pass
to ctime, so use a temporary */
time_t sec = notice->z_time.tv_sec;
when = ctime(&sec);
}
time_string = string_CreateFromData(when+11,8);
var_set_variable_then_free_value("time", time_string);
date_string = string_Concat(notyear=string_CreateFromData(when,11),
year=string_CreateFromData(when+20,4));
var_set_variable_then_free_value("date", date_string);
free(notyear);
free(year);
/*
* Convert host notice sent from to ascii:
*/
var_set_variable("fromhost", hostname ? hostname :
inet_ntoa(notice->z_sender_addr));
/*
* Set $message to the message field of the notice with nulls changed
* to newlines:
*/
var_set_variable_then_free_value("message",
convert_nulls_to_newlines(notice->z_message,
notice->z_message_len));
/*
* Decide if its a control notice. If so, return the notice's
* opcode. Otherwise, return NULL:
*/
if ((strcasecmp(notice->z_class, WG_CTL_CLASS)==0) && /* <<<>>> */
(strcasecmp(notice->z_class_inst, WG_CTL_USER)==0))
return(notice->z_opcode);
return(0);
}

75
zwgc/notice.h Normal file
View File

@ -0,0 +1,75 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef notice_MODULE
#define notice_MODULE
#include <zephyr/zephyr.h>
#include "new_string.h"
/*
* int count_nulls(char *data, int length)
* Requires: length>=0
* Effects: Returns the # of nulls in data[0]..data[length-1]
*/
extern int count_nulls(char *, int);
/*
* string get_next_field(char **data_p, int *length_p)
* Requires: *length_p >= 0
* Modifies: *data_p, *length_p
* Effects: Treats (*data_p)[0], (*data_p)[1], ... (*data_p)[length-1]
* as a series of null-seperated fields. This function
* returns a copy of the first field on the heap. This
* string must eventually be freed. Also, *data_p is
* advanced and *length_p decreased so that another
* call to this procedure with the same arguments will
* return the second field. The next call will return
* the third field, etc. "" is returned if 0 fields
* remain. (this is the case when *length_p == 0)
*/
extern string get_next_field(char **, int *);
/*
* string get_field(char *data, int length, int num)
* Requires: length>=0, num>0
* Effects: Treats data[0]..data[length-1] as a series of
* null-seperated fields. This function returns a copy of
* the num'th field (numbered from 1 in this case) on the
* heap. This string must eventually be freed. If there
* is no num'th field (because num<1 or num># of fields),
* "" is returned.
*/
extern string get_field(char *, int, int);
/*
* string convert_nulls_to_newlines(data, length)
* Requires: length>=0, malloc never returns NULL
* Effects: Takes data[0]..data[length-1], converts all nulls to
* newlines ('\n') and returns the result as a null-terminated
* string on the heap. The returned string must eventually
* be freed.
*/
extern string convert_nulls_to_newlines(char *, int);
extern char *decode_notice(ZNotice_t *, char *);
#endif

54
zwgc/parser.h Normal file
View File

@ -0,0 +1,54 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef parser_MODULE
#define parser_MODULE
/*
* Parser-Lexer Internal Routine:
*
* void report_parse_error(char *error_message, int line_number)
* Modifies: error_occured, stderr
* Effects: This routine is called to report a parser or lexer
* error. Error_message is the error message and line_number
* the line number it occured on. The reported error message
* is of the form "....<error_message> on line <line #>.\n".
* This routine sets error_occured (local to parser.y) to
* true. If it was previously false, the error message
* is reported to the user via stderr.
*/
extern void report_parse_error(char *, int);
/*
* struct _Node *parse_file(FILE *input_file)
* Requires: input_file is opened for reading, no pointers to
* existing nodes will ever be dereferened.
* Modifies: *input_file, stderr, all existing nodes
* Effects: First this routine destroys all nodes. Then it parses
* input_file as a zwgc description langauge file. If
* an error is encountered, an error message is printed
* on stderr and NULL is returned. If no error is
* encountered, a pointer to the node representation of
* the parsed program is returned, suitable for passing to
* exec.c. Note that NULL will also be returned for a
* empty file & is a valid program. Either way, input_file
* is closed before this routine returns.
*/
extern struct _Node *parse_file(FILE *);
#endif

387
zwgc/parser.y Normal file
View File

@ -0,0 +1,387 @@
%{
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_parser_y[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/* Saber-C suppressions because yacc loses */
/*SUPPRESS 288*/
/*SUPPRESS 287*/
#include <stdio.h>
#include "lexer.h"
#include "parser.h"
#include "node.h"
#include "zwgc.h"
static void yyerror(char *);
/*
* the_program - local variable used to communicate the program's node
* representation from the program action to the parse_file
* function.
*/
static Node *the_program;
%}
%union{
char *text;
struct _Node *node;
}
%start program
%token ERROR
%token <text> VARNAME VARREF STRING SHOW
%token APPENDPORT BUFFER BREAK CLOSEINPUT CLOSEOUTPUT
%token CLOSEPORT CASE CLEARBUF DEFAULT DISPLAY DO DOWNCASE
%token ELSE ELSEIF ENDCASE ENDIF ENDWHILE EXEC EXECPORT EXIT
%token FIELDS GET GETENV IF INPUTPORT LANY LBREAK LSPAN
%token MATCH NOOP NOT OUTPUTPORT PRINT PROTECT VERBATIM PUT RANY RBREAK
%token RSPAN SET SUBSTITUTE THEN UPCASE WHILE ZVAR STYLESTRIP
%type <node> expr varname string
%type <node> exprlist comma_exprlist varnamelist
%type <node> statement statements program elseparts elseifparts
%type <node> match matchlist
%left '|'
%left '&'
%left EQ NEQ REGEQ REGNEQ
%left '+'
%left '!'
%%
/*
* A program is simply a list of statements: (may be NULL if no statements...)
*/
program : statements
{ the_program = reverse_list_of_nodes($1);
$$ = the_program; }
;
varname : VARNAME
{ $$ = node_create_string_constant(VARNAME_OPCODE, $1); }
;
string : STRING
{ $$ = node_create_string_constant(STRING_CONSTANT_OPCODE, $1); }
;
expr : '(' expr ')'
{ $$ = $2; }
| string
{ $$ = $1; }
| VARREF
{ $$ = node_create_string_constant(VARREF_OPCODE, $1); }
| '!' expr
{ $$ = node_create_unary(NOT_OPCODE, $2); }
| expr '+' expr
{ $$ = node_create_binary(PLUS_OPCODE, $1, $3); }
| expr '|' expr /* note "or" == '|' */
{ $$ = node_create_binary(OR_OPCODE, $1, $3); }
| expr '&' expr /* note "and" == '&' */
{ $$ = node_create_binary(AND_OPCODE, $1, $3); }
| expr EQ expr
{ $$ = node_create_binary(EQ_OPCODE, $1, $3); }
| expr NEQ expr
{ $$ = node_create_binary(NEQ_OPCODE, $1, $3); }
| expr REGEQ expr
{ $$ = node_create_binary(REGEQ_OPCODE, $1, $3); }
| expr REGNEQ expr
{ $$ = node_create_binary(REGNEQ_OPCODE, $1, $3); }
| BUFFER '(' ')'
{ $$ = node_create_noary(BUFFER_OPCODE); }
| SUBSTITUTE '(' expr ')'
{ $$ = node_create_unary(SUBSTITUTE_OPCODE, $3); }
| PROTECT '(' expr ')'
{ $$ = node_create_unary(PROTECT_OPCODE, $3); }
| VERBATIM '(' expr ')'
{ $$ = node_create_unary(VERBATIM_OPCODE, $3); }
| GETENV '(' expr ')'
{ $$ = node_create_unary(GETENV_OPCODE, $3); }
| UPCASE '(' expr ')'
{ $$ = node_create_unary(UPCASE_OPCODE, $3); }
| DOWNCASE '(' expr ')'
{ $$ = node_create_unary(DOWNCASE_OPCODE, $3); }
| ZVAR '(' expr ')'
{ $$ = node_create_unary(ZVAR_OPCODE, $3); }
| GET '(' expr ')'
{ $$ = node_create_unary(GET_OPCODE, $3); }
| STYLESTRIP '(' expr ')'
{ $$ = node_create_unary(STYLESTRIP_OPCODE, $3); }
| LANY '(' expr ',' expr ')'
{ $$ = node_create_binary(LANY_OPCODE, $3, $5 ); }
| RANY '(' expr ',' expr ')'
{ $$ = node_create_binary(RANY_OPCODE, $3, $5 ); }
| LBREAK '(' expr ',' expr ')'
{ $$ = node_create_binary(LBREAK_OPCODE, $3, $5 ); }
| RBREAK '(' expr ',' expr ')'
{ $$ = node_create_binary(RBREAK_OPCODE, $3, $5 ); }
| LSPAN '(' expr ',' expr ')'
{ $$ = node_create_binary(LSPAN_OPCODE, $3, $5 ); }
| RSPAN '(' expr ',' expr ')'
{ $$ = node_create_binary(RSPAN_OPCODE, $3, $5 ); }
;
statement : NOOP
{ $$ = node_create_noary(NOOP_OPCODE); }
| SET varname '=' expr
{ $$ = node_create_binary(SET_OPCODE, $2, $4); }
| FIELDS varnamelist
{ $$ = node_create_unary(FIELDS_OPCODE,
reverse_list_of_nodes($2)); }
/*
* Output to & control of output buffer statements:
*/
| PRINT exprlist
{ $$ = node_create_unary(PRINT_OPCODE,
reverse_list_of_nodes($2)); }
| SHOW
{ $$ = node_create_unary(PRINT_OPCODE,
node_create_unary(SUBSTITUTE_OPCODE,
node_create_string_constant(STRING_CONSTANT_OPCODE,
$1))); }
| CLEARBUF
{ $$ = node_create_noary(CLEARBUF_OPCODE); }
/*
* Statements to manage ports:
*/
| APPENDPORT expr expr
{ $$ = node_create_binary(APPENDPORT_OPCODE, $2, $3); }
| EXECPORT expr expr exprlist
{ $3->next = reverse_list_of_nodes($4);
$$ = node_create_binary(EXECPORT_OPCODE, $2, $3); }
| INPUTPORT expr expr
{ $$ = node_create_binary(INPUTPORT_OPCODE, $2, $3); }
| OUTPUTPORT expr expr
{ $$ = node_create_binary(OUTPUTPORT_OPCODE, $2, $3); }
| PUT expr exprlist
{ $$ = node_create_binary(PUT_OPCODE, $2,
reverse_list_of_nodes($3)); }
| PUT
{ $$ = node_create_binary(PUT_OPCODE, 0, 0); }
| CLOSEINPUT expr
{ $$ = node_create_unary(CLOSEINPUT_OPCODE, $2); }
| CLOSEOUTPUT expr
{ $$ = node_create_unary(CLOSEOUTPUT_OPCODE, $2); }
| CLOSEPORT expr
{ $$ = node_create_unary(CLOSEPORT_OPCODE, $2); }
/*
* Statements to run subprocesses without I/O to them:
*/
| EXEC expr exprlist
{ $2->next = reverse_list_of_nodes($3);
$$ = node_create_unary(EXEC_OPCODE, $2); }
/*
* Control statements:
*/
| IF expr THEN statements elseparts ENDIF
{ Node *n = node_create_binary(IF_OPCODE, $2,
reverse_list_of_nodes($4));
n->next = $5;
$$ = node_create_unary(IF_STMT_OPCODE, n); }
| CASE expr matchlist ENDCASE
{ $$ = node_create_binary(CASE_OPCODE, $2,
reverse_list_of_nodes($3)); }
| WHILE expr DO statements ENDWHILE
{ $$ = node_create_binary(WHILE_OPCODE, $2,
reverse_list_of_nodes($4)); }
| BREAK
{ $$ = node_create_noary(BREAK_OPCODE); }
| EXIT
{ $$ = node_create_noary(EXIT_OPCODE); }
;
elseparts : elseifparts
{ $$ = reverse_list_of_nodes($1); }
| elseifparts ELSE statements
{ $$ = node_create_binary(ELSE_OPCODE, 0,
reverse_list_of_nodes($3));
$$->next = $1;
$$ = reverse_list_of_nodes($$); }
;
/* elseifparts needs to be reversed before using... */
elseifparts : /* empty */
{ $$ = 0; }
| elseifparts ELSEIF expr THEN statements
{ $$ = node_create_binary(ELSEIF_OPCODE, $3,
reverse_list_of_nodes($5));
$$->next = $1; }
;
match : MATCH comma_exprlist statements
{ $$ = node_create_binary(MATCHLIST_OPCODE,
reverse_list_of_nodes($2),
reverse_list_of_nodes($3)); }
| DEFAULT statements
{ $$ = node_create_binary(DEFAULT_OPCODE, 0,
reverse_list_of_nodes($2)); }
;
/*
* Various lists of non-terminals like expr's and varname's. Each is
* built up as a linked list using the nodes' next fields. To prevent
* Yacc stack overflow on long lists, these are put on the linked list
* BACKWARDS. The user of these must first call reverse_list_of_nodes
* on one of these before using it. All except comma_exprlist
* allow 0 elements on the list in which case their value is NULL.
* (comma_exprlist requires at least one element)
*/
exprlist : /* empty */
{ $$ = 0; }
| exprlist expr
{ $$ = $2;
$$->next = $1; }
;
comma_exprlist : expr
{ $$ = $1; }
| comma_exprlist ',' expr
{ $$ = $3;
$$->next = $1; }
;
varnamelist : /* empty */
{ $$ = 0; }
| varnamelist varname
{ $$ = $2;
$$->next = $1; }
;
matchlist : /* empty */
{ $$ = 0; }
| matchlist match
{ $$ = $2;
$$->next = $1; }
;
statements : /* empty */
{ $$ = 0; }
| statements statement
{ $$ = $2;
$$->next = $1; }
;
%%
/*
* error_occured - Set to true when a parse error is reported. If it is false
* at the time a parse error is reported, a message is
* printed on stderr. See report_parse_error for more
* details.
*/
static int error_occured = 0;
/*
* Parser-Lexer Internal Routine:
*
* void report_parse_error(char *error_message, int line_number)
* Modifies: error_occured, stderr
* Effects: This routine is called to report a parser or lexer
* error. Error_message is the error message and line_number
* the line number it occured on. The reported error message
* is of the form "....<error_message> on line <line #>.\n".
* This routine sets error_occured (local to parser.y) to
* true. If it was previously false, the error message
* is reported to the user via stderr.
*/
void
report_parse_error(char *error_message,
int line_number)
{
if (error_occured)
return;
error_occured = 1;
fprintf(stderr, "zwgc: error in description file: %s on line %d.\n",
error_message, line_number);
fflush(stderr);
}
/*
* yyerror - internal routine - used by yacc to report syntax errors and
* stack overflow errors.
*/
static void yyerror(char *message)
{
report_parse_error(message, yylineno);
}
/*
* struct _Node *parse_file(FILE *input_file)
* Requires: input_file is opened for reading, no pointers to
* existing nodes will ever be dereferened.
* Modifies: *input_file, stderr, all existing nodes
* Effects: First this routine destroys all nodes. Then it parses
* input_file as a zwgc description langauge file. If
* an error is encountered, an error message is printed
* on stderr and NULL is returned. If no error is
* encountered, a pointer to the node representation of
* the parsed program is returned, suitable for passing to
* exec.c. Note that NULL will also be returned for a
* empty file & is a valid program. Either way, input_file
* is closed before this routine returns.
*/
struct _Node *
parse_file(FILE *input_file)
{
the_program = NULL;
error_occured = 0;
node_DestroyAllNodes();
lex_open(input_file);
yyparse();
fclose(input_file);
if (error_occured) {
node_DestroyAllNodes();
the_program = NULL;
}
#ifdef DEBUG
if (zwgc_debug) {
printf("****************************************************************************\n");
node_display(the_program);
printf("****************************************************************************\n");
}
#endif
return(the_program);
}

499
zwgc/plus.c Normal file
View File

@ -0,0 +1,499 @@
/*
This file contains code related to the zwgcplus extension to zwgc.
zwgc is copyrighted by the Massachusetts Institute of Technology.
This file is public domain.
Written by Andrew Plotkin, ap1i+@andrew.cmu.edu
Timequeue code added by Ryan Ingram, ryani+@andrew.cmu.edu
Rewritten for incorporation into MIT zwgc from 2.0.2 by Derrick Brashear
*/
#include <sysdep.h>
#ifdef CMU_ZWGCPLUS
#if (!defined(lint) && !defined(SABER))
static const char rcsid_plus_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
#include <zephyr/zephyr.h>
#include "new_memory.h"
#include "node.h"
#include "exec.h"
#include "eval.h"
#include "node.h"
#include "buffer.h"
#include "port.h"
#include "variables.h"
#include "notice.h"
#include "X_gram.h"
#include "xrevstack.h"
#include "main.h"
#include "plus.h"
int get_full_names = 0;
#define HASHSIZE (251)
typedef struct timenode_s {
ZNotice_t *notice;
struct timenode_s *next;
time_t when;
char *event_name;
} TimeNode;
typedef struct _notnode {
ZNotice_t *notice;
int fake_notice; /* if TRUE, do not call ZFreeNotice() */
int refcount;
struct _notnode *next;
char *opcode;
char *hname;
} notnode;
static ZNotice_t *stored_notice;
static notnode *notlist[HASHSIZE];
TimeNode *timeq_head = NULL;
int list_hash_fun(ZNotice_t *notice);
static TimeNode *
addtimenode(TimeNode *head, TimeNode *node)
{
if(head == NULL) {
#ifdef DEBUG_TIMEQUEUE
fprintf(stderr, "adding new timenode; creating queue\n");
#endif
node->next = NULL;
return node;
}
if(head->when > node->when) {
#ifdef DEBUG_TIMEQUEUE
fprintf(stderr, "adding new timenode at start of queue\n");
#endif
node->next = head;
return node;
}
head->next = addtimenode(head->next, node);
return head;
}
static void
handle_timeq_event(TimeNode *event)
{
char buf[128];
notnode *pt;
int bx = list_hash_fun(event->notice);
for (pt=notlist[bx]; pt && pt->notice!=event->notice; pt=pt->next);
/* "time-" + event_name + '\0' */
#ifdef DEBUG_TIMEQUEUE
fprintf(stderr, "handle_timeq_event()\n");
#endif
if (strlen(event->event_name)<123)
sprintf(buf, "time-%s", event->event_name);
else
sprintf(buf, "time-bogus");
#ifdef DEBUG_TIMEQUEUE
fprintf(stderr, "opcode: %s\n", buf);
#endif
event->notice->z_version = "zwgcplus-repeat";
event->notice->z_opcode = buf;
reprocess_notice(event->notice, pt->hname);
#ifdef DEBUG_TIMEQUEUE
fprintf(stderr, "end handle_timeq_event()\n");
#endif
}
static void
schedule_event(long secs, char *name, ZNotice_t *notice)
{
time_t eventtime = (time(NULL)) + secs;
TimeNode *newnode;
char *buf;
#ifdef DEBUG_TIMEQUEUE
fprintf(stderr, "schedule_event(%ld, %ld, %s)\n", eventtime, secs, name);
#endif
if(!notice || !name) return;
list_add_notice(notice);
newnode = (TimeNode *)malloc(sizeof(TimeNode));
buf = (char *)malloc(strlen(name) + 1);
strcpy(buf, name);
#ifdef DEBUG_TIMEQUEUE
fprintf(stderr, "name: %s\n", buf);
#endif
newnode->when = eventtime;
newnode->event_name = buf;
newnode->notice = notice;
timeq_head = addtimenode(timeq_head, newnode);
#ifdef DEBUG_TIMEQUEUE
fprintf(stderr, "end schedule_event()\n");
#endif
}
static void
free_timenode(TimeNode *node)
{
#ifdef DEBUG_TIMEQUEUE
fprintf(stderr, "free_timenode(%s)\n", node->event_name);
#endif
free(node->event_name);
free(node);
}
/* returns the number of notices destroyed */
static int
destroy_timeq_notice(ZNotice_t *notice, char *name)
{
TimeNode *curr = timeq_head;
TimeNode *prev = NULL;
TimeNode *tmp;
int ct = 0;
#ifdef DEBUG_TIMEQUEUE
fprintf(stderr, "destroy_timeq_notice(%s)\n", name);
#endif
while(curr != NULL) {
if(curr->notice == notice &&
(!name || !strcmp(curr->event_name, name)))
{
ct++;
if(!prev) {
timeq_head = curr->next;
} else {
prev->next = curr->next;
}
tmp = curr;
curr = curr->next;
free_timenode(tmp);
} else {
prev = curr;
curr = curr->next;
}
}
return ct;
}
long
plus_timequeue_events(void)
{
/* returns number of seconds to the next event or 0L */
/* if there are no events remaining to be processed */
time_t timenow = time(NULL);
TimeNode *curr;
while(timeq_head != NULL && timeq_head->when <= timenow) {
#ifdef DEBUG_TIMEQUEUE
fprintf(stderr, "handling event\n");
#endif
handle_timeq_event(timeq_head);
curr = timeq_head;
timeq_head = timeq_head->next;
free_timenode(curr);
}
#ifdef DEBUG_TIMEQUEUE
if(timeq_head != NULL)
fprintf(stderr, "next event in %ld seconds.\n",
(timeq_head->when) - timenow);
#endif
return ((timeq_head == NULL) ? 0L : ((timeq_head->when) - timenow));
}
void
plus_set_hname(ZNotice_t *notice, char *hname)
{
notnode *pt;
int bx;
if (hname) {
bx = list_hash_fun(notice);
for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
pt->hname=(char *)malloc(strlen(hname)+1);
strcpy(pt->hname, hname);
}
return;
}
void
plus_queue_notice(ZNotice_t *notice)
{
char *val;
int howlong = 0;
#ifdef DEBUG_TIMEQUEUE
fprintf(stderr, "plus_queue_notice()\n");
#endif
val = var_get_variable("event_time");
if(val) {
if(strcmp(val, "kill")) {
howlong = atoi(val);
#ifdef DEBUG_TIMEQUEUE
fprintf(stderr, "$event_time %d\n", howlong);
#endif
} else {
val = var_get_variable("event_name");
if(!val || strcmp(val, "all"))
destroy_timeq_notice(notice, (val && val[0]) ? val : "event");
else
destroy_timeq_notice(notice, (char *)NULL);
}
}
if(howlong > 0) {
val = var_get_variable("event_name");
#ifdef DEBUG_TIMEQUEUE
fprintf(stderr, "$event_name = %s\n", val);
#endif
schedule_event(howlong, (val && val[0]) ? val : "event", notice);
}
}
int
list_hash_fun(ZNotice_t *notice)
{
unsigned int ix;
int res = 0, val = 1, ptval;
char *pt = (char *)(notice);
for (ix=0; ix<sizeof(ZNotice_t *); ix++) {
ptval = (int)pt[ix];
if (ptval<0) ptval = (-ptval);
res += val * ptval;
res %= HASHSIZE;
val *= 7;
};
return res;
}
/* initialize hash table */
void
init_noticelist(void)
{
int ix;
stored_notice = NULL;
for (ix=0; ix<HASHSIZE; ix++) {
notlist[ix] = NULL;
}
}
void
dump_noticelist(void)
{
notnode *pt;
int bx;
for (bx=0; bx<HASHSIZE; bx++) {
for (pt=notlist[bx]; pt; pt=pt->next) {
fprintf(stderr, "Not %p: %d [%d]\n", (void *)pt->notice,
pt->refcount, bx);
}
}
}
/* add notice to table. Either generate a new entry, or increment ref count. */
void
list_add_notice(ZNotice_t *notice)
{
notnode *pt;
int bx = list_hash_fun(notice);
for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
if (pt) {
/* found entry */
pt->refcount++;
}
else {
/* no entry */
pt = (notnode *)malloc(sizeof(notnode));
pt->notice = notice;
pt->refcount = 1;
pt->fake_notice = 0;
pt->next = notlist[bx];
pt->opcode = notice->z_opcode;
pt->hname = NULL;
notlist[bx] = pt;
}
/*fprintf(stderr, "list_add_notice(%p)\n", notice);
dump_noticelist();*/
}
/* remove notice from table. If refcount reaches 0, return 1; if refcount is
still positive, return 0; if notice not there, return -1. */
int
list_del_notice(ZNotice_t *notice)
{
notnode *pt, **ppt;
int bx = list_hash_fun(notice);
for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
if (!pt) {
/* no entry */
/*fprintf(stderr, "list_del_notice(%p): ERROR\n", notice);
dump_noticelist();*/
return (-1);
}
pt->refcount--;
if (pt->refcount > 0) {
/*fprintf(stderr, "list_del_notice(%p): count %d\n", notice, pt->refcount);
dump_noticelist();*/
return 0;
}
for (ppt = &(notlist[bx]); (*ppt)!=pt; ppt = &((*ppt)->next));
*ppt = (*ppt)->next;
if (!pt->fake_notice)
ZFreeNotice(pt->notice);
if (pt->hname)
free(pt->hname);
free(pt->notice);
free(pt);
/*fprintf(stderr, "list_del_notice(%p): count 0, gone\n", notice);*/
/*dump_noticelist();*/
return 1;
}
void
set_notice_fake(ZNotice_t *notice, int val)
{
notnode *pt;
int bx = list_hash_fun(notice);
for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
if (pt) {
pt->fake_notice = val;
}
}
int
get_notice_fake(ZNotice_t *notice)
{
notnode *pt;
int bx = list_hash_fun(notice);
for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
if (pt) {
return pt->fake_notice;
}
else
return 0;
}
int
get_list_refcount(ZNotice_t *notice)
{
notnode *pt;
int bx = list_hash_fun(notice);
for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
if (pt) {
/*fprintf(stderr, "get_list_refcount(%p): count %d\n", notice, pt->refcount);*/
return pt->refcount;
}
else {
/*fprintf(stderr, "get_list_refcount(%p): count 0\n", notice);*/
return 0;
}
}
/* export a reference to the current notice. */
ZNotice_t *
get_stored_notice(void)
{
if (!stored_notice)
return NULL;
list_add_notice(stored_notice);
return stored_notice;
}
void
set_stored_notice(ZNotice_t *notice)
{
stored_notice = notice;
}
void
plus_retry_notice(ZNotice_t *notice, char ch, int metaflag)
{
char buf[128];
char *tmp;
notnode *pt;
int bx;
if (!notice)
return;
bx = list_hash_fun(notice);
for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next);
if (metaflag) tmp = "-meta";
else tmp = "";
if (ch==' ')
sprintf(buf, "key%s-space", tmp);
else if (ch==127)
sprintf(buf, "key%s-delete", tmp);
else if (ch==0)
sprintf(buf, "key%s-ctrl-@", tmp);
else if (ch==27)
sprintf(buf, "key%s-esc", tmp);
else if (isprint(ch))
sprintf(buf, "key%s-%c", tmp, ch);
else if (ch>=1 && ch<=26)
sprintf(buf, "key%s-ctrl-%c", tmp, ch+'a'-1);
else if (iscntrl(ch))
sprintf(buf, "key%s-ctrl-%c", tmp, ch+'A'-1);
else
sprintf(buf, "key%s-unknown", tmp);
/* concat the old opcode if they're running in "new" mode */
if (zwgcplus == 2 && pt && pt->opcode[0] &&
strcmp(pt->opcode, "") != 0)
{
strcat(buf, " ");
strncat(buf, pt->opcode, sizeof(buf)-strlen(buf));
}
notice->z_version = "zwgcplus-repeat";
notice->z_opcode = buf;
reprocess_notice(notice, NULL);
}
#endif /* CMU_ZWGCPLUS */

29
zwgc/plus.h Normal file
View File

@ -0,0 +1,29 @@
/*
This file contains code related to the zwgcplus extension to zwgc.
zwgc is copyrighted by the Massachusetts Institute of Technology.
This file is public domain.
Written by Andrew Plotkin, ap1i+@andrew.cmu.edu
*/
#define NAMESIZE (256)
extern int get_full_names;
extern int zwgcplus;
extern void init_noticelist(void);
extern void dump_noticelist(void);
extern void list_add_notice(ZNotice_t *notice);
extern int list_del_notice(ZNotice_t *notice);
extern int get_list_refcount(ZNotice_t *notice);
extern void set_notice_fake(ZNotice_t *notice, int val);
extern int get_notice_fake(ZNotice_t *notice);
extern ZNotice_t *get_stored_notice(void);
extern void plus_retry_notice(ZNotice_t *notice, char ch, int metaflag);
extern void set_stored_notice(ZNotice_t *notice);
extern void plus_window_deletions(ZNotice_t *notice); /* actually in xshow.c */
extern void plus_queue_notice(ZNotice_t *notice);
extern long plus_timequeue_events(void);
void plus_set_hname(ZNotice_t *notice, char *hname);
extern char *getSelectedText(void); /* actually in xcut.c */

26
zwgc/pointer.h Normal file
View File

@ -0,0 +1,26 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef pointer_MODULE
#define pointer_MODULE
#ifdef __STDC__
typedef void *pointer;
#else
typedef char *pointer;
#endif
#endif

656
zwgc/port.c Normal file
View File

@ -0,0 +1,656 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_port_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* The Implementation of the port type: */
/* */
/****************************************************************************/
#include "new_string.h"
#include "port_dictionary.h"
#include "port.h"
#include "notice.h"
#include "variables.h"
/****************************************************************************/
/* */
/* Port methods (internal): */
/* */
/****************************************************************************/
static string
port_get(port *p)
{
char *(*get_proc)(port *, char **);
char *error = NULL;
char *result;
if (p->status & INPUT_CLOSED) {
var_set_variable("error",
"Attempt to read from a port whose input has been closed");
return(string_Copy(""));
}
get_proc = p->get;
if (!get_proc) {
var_set_variable("error",
"Attempt to read from a port which does not support reading");
return(string_Copy(""));
}
result = get_proc(p, &error);
if (!result) {
var_set_variable("error", error);
return(string_Copy(""));
} else
return(result);
}
static void
port_put(port *p,
char *data,
int length)
{
char *(*put_proc)(port *, char *, int);
char *error;
if (p->status & OUTPUT_CLOSED) {
var_set_variable("error",
"Attempt to write to a port whose output has been closed");
return;
}
put_proc = p->put;
if (!put_proc) {
var_set_variable("error",
"Attempt to write to a port which does not support writing");
return;
}
error = put_proc(p, data, length);
if (error)
var_set_variable("error", error);
}
static void
port_close_input(port *p)
{
char *(*close_input_proc)(port *);
char *error;
if (p->status & INPUT_CLOSED)
return;
p->status |= INPUT_CLOSED;
close_input_proc = p->close_input;
if (!close_input_proc)
return;
error = close_input_proc(p);
if (error)
var_set_variable("error", error);
}
static void
port_close_output(port *p)
{
char *(*close_output_proc)(port *);
char *error;
if (p->status & OUTPUT_CLOSED)
return;
p->status |= OUTPUT_CLOSED;
close_output_proc = p->close_output;
if (!close_output_proc)
return;
error = close_output_proc(p);
if (error)
var_set_variable("error", error);
}
/****************************************************************************/
/* */
/* Code to implement a namespace of ports: */
/* */
/****************************************************************************/
/*
* port_dict - the dictionary mapping portnames to ports
*/
static port_dictionary port_dict = NULL;
/*
* void init_ports()
* Modifies: all ports
* Effects: Closes all existing ports. Must be called before
* any other port call is made.
*/
static void
close_port_from_binding(port_dictionary_binding *b)
{
port_close_input(&(b->value));
port_close_output(&(b->value));
}
void
init_ports(void)
{
if (port_dict) {
port_dictionary_Enumerate(port_dict, close_port_from_binding);
port_dictionary_Destroy(port_dict);
}
port_dict = port_dictionary_Create(31);
}
/*
* Internal Routine:
*
* port *create_named_port(string name)
* Modifies: the port named name
* Requires: init_ports has been called
* Effects: If a port with name name already exists, it is first
* closed (& destroyed). A new unfilled in port is then
* created and assigned the name name. Its address is
* then returned. It is up to the caller to fill in its
* various fields correctly.
*/
static port *
create_named_port(string name)
{
int already_exists;
port_dictionary_binding *binding;
binding = port_dictionary_Define(port_dict, name, &already_exists);
if (already_exists) {
port_close_input(&(binding->value));
port_close_output(&(binding->value));
}
return(&(binding->value));
}
/*
* Internal Routine:
*
* port *get_named_port(string name)
* Requires: init_ports has been called
* Effects: If there is a port by name name, returns a pointer to
* it. Otherwise returns NULL.
*/
static port *
get_named_port(string name)
{
port_dictionary_binding *binding;
binding = port_dictionary_Lookup(port_dict, name);
if (!binding)
return(NULL);
return(&(binding->value));
}
/****************************************************************************/
/* */
/* External interface to named ports: */
/* */
/****************************************************************************/
/*
* string read_from_port(string name)
* Requires: init_ports has been called
* Modifies: the port named name if any, $error
* Effects: If a port by name name does not exist, sets $error to
* "No such port" & returns "". Otherwise, attempts to
* read from that port. If an error occurs, $error is
* set to the error message and "" returned. Otherwise
* the read string is returned. The returned string is
* on the heap & must be eventually freed.
*/
string
read_from_port(string name)
{
port *p;
if (!(p = get_named_port(name))) {
var_set_variable("error", "No such port");
return(string_Copy(""));
}
return(port_get(p));
}
/*
* void write_on_port(string name, char *text, int length)
* Requires: init_ports has been called, length>=0
* Modifies: the port named name if any, $error
* Effects: If a port by name name does not exist, sets $error to
* "No such port" & returns. Otherwise, attempts to
* write text[0..length-1] on that port. If an error
* occurs, $error is set to the error message.
*/
void
write_on_port(string name,
char *text,
int length)
{
port *p;
if (!(p = get_named_port(name))) {
var_set_variable("error", "No such port");
return;
}
port_put(p, text, length);
}
/*
* void close_port_input(string name)
* Requires: init_ports has been called
* Modifies: the port named name if any, $error
* Effects: If a port by name name does not exist, sets $error to
* "No such port" & returns. Otherwise, closes the
* input part of the port by name name. When both a
* port's input & output parts have been closed, the
* port is deleted to save space. If an error
* occurs, $error is set to the error message.
*/
void
close_port_input(string name)
{
port_dictionary_binding *binding;
binding = port_dictionary_Lookup(port_dict, name);
if (!binding)
return;
port_close_input(&(binding->value));
if (binding->value.status == PORT_CLOSED)
port_dictionary_Delete(port_dict, binding);
}
/*
* void close_port_output(string name)
* Requires: init_ports has been called
* Modifies: the port named name if any, $error
* Effects: If a port by name name does not exist, sets $error to
* "No such port" & returns. Otherwise, closes the
* output part of the port by name name. When both a
* port's input & output parts have been closed, the
* port is deleted to save space. If an error
* occurs, $error is set to the error message.
*/
void
close_port_output(string name)
{
port_dictionary_binding *binding;
binding = port_dictionary_Lookup(port_dict, name);
if (!binding)
return;
port_close_output(&(binding->value));
if (binding->value.status == PORT_CLOSED)
port_dictionary_Delete(port_dict, binding);
}
/****************************************************************************/
/* */
/* Code to implement a port given some FILE *'s: */
/* */
/****************************************************************************/
static string
get_file(port *p,
char **error_p)
{
char buffer[10000]; /* <<<>>> */
if (!p->data.file.input_connector) {
*error_p = "Attempt to read past end of file";
return(NULL);
}
buffer[0] = 0;
errno = 0;
if (!fgets(buffer, 9999, p->data.file.input_connector)) {
if (errno)
*error_p = strerror(errno);
else
*error_p = "Attempt to read past end of file";
return(NULL);
}
buffer[9999] = 0;
return(string_Copy(buffer));
}
static char *
put_file(port *p,
string text,
int length)
{
if (!p->data.file.output_connector)
return(NULL);
errno = 0;
fwrite(text, 1, length, p->data.file.output_connector);
fflush(p->data.file.output_connector);
if (errno)
return(strerror(errno));
return(NULL);
}
static char *
close_file_input(port *p)
{
errno = 0;
if (p->data.file.input_connector) {
fclose(p->data.file.input_connector);
p->data.file.input_connector = 0;
}
if (errno)
return(strerror(errno));
return(NULL);
}
static char *
close_file_output(port *p)
{
errno = 0;
if (p->data.file.output_connector) {
fclose(p->data.file.output_connector);
p->data.file.output_connector = 0;
}
if (errno)
return(strerror(errno));
return(NULL);
}
void create_port_from_files(string name,
FILE *input,
FILE *output)
{
port *p = create_named_port(name);
#if !defined(__HIGHC__)
p->get = input ? get_file : NULL;
p->put = output ? put_file : NULL;
#else
/* RT compiler (hc2.1y) bug workaround */
if (input)
p->get = get_file;
else
p->get = NULL;
if (output)
p->put = put_file;
else
p->put = NULL;
#endif
p->close_input = close_file_input;
p->close_output = close_file_output;
p->status = 0;
p->data.file.input_connector = input;
p->data.file.output_connector = output;
}
/****************************************************************************/
/* */
/* Code for creating various types of FILE * ports: */
/* */
/****************************************************************************/
void
create_subprocess_port(string name,
char **argv)
{
int pid;
int to_child_descriptors[2];
int to_parent_descriptors[2];
FILE *in = 0;
FILE *out = 0;
/* <<<>>> (file leak) */
if (pipe(to_child_descriptors)!=0 || pipe(to_parent_descriptors)!=0)
return;
pid = fork();
if (pid == -1) {
fprintf(stderr, "zwgc: error while attempting to fork: ");
perror("");
return; /* <<<>>> */
} else if (pid == 0) { /* in child */
close(0);
close(1);
dup2(to_child_descriptors[0], 0);
dup2(to_parent_descriptors[1], 1);
close(to_child_descriptors[1]);
close(to_parent_descriptors[0]);
execvp(argv[0], argv);
fprintf(stderr,"zwgc: unable to exec %s: ", argv[0]);
perror("");
_exit(errno);
}
fcntl(to_parent_descriptors[0], F_SETFD, 1);
fcntl(to_child_descriptors[1], F_SETFD, 1);
in = fdopen(to_parent_descriptors[0],"r");
out = fdopen(to_child_descriptors[1],"w");
close(to_child_descriptors[0]);
close(to_parent_descriptors[1]);
create_port_from_files(name, in, out);
}
void
create_file_append_port(string name,
string filename)
{
FILE *out;
int oumask;
errno = 0;
oumask = umask(077); /* allow read/write for us only */
out = fopen(filename, "a");
(void) umask(oumask);
if (out == NULL) {
var_set_variable("error", strerror(errno));
return;
}
create_port_from_files(name, 0, out);
}
void
create_file_input_port(string name,
string filename)
{
FILE *in;
errno = 0;
in = fopen(filename, "r");
if (in == NULL) {
var_set_variable("error", strerror(errno));
return;
}
create_port_from_files(name, in, 0);
}
void
create_file_output_port(string name,
string filename)
{
FILE *out;
int oumask;
errno = 0;
oumask = umask(077); /* allow read/write for us only */
out = fopen(filename, "w");
(void) umask(oumask);
if (out == NULL) {
var_set_variable("error", strerror(errno));
return;
}
create_port_from_files(name, 0, out);
}
/****************************************************************************/
/* */
/* Code to implement a port given a filter function: */
/* */
/****************************************************************************/
static string
get_filter(port *p,
char **error_p)
{
string result;
if (string_stack_empty(p->data.filter.waiting_packets)) {
*error_p = "Attempt to read from port when no data available";
return(NULL);
}
result = string_stack_top(p->data.filter.waiting_packets);
string_stack_pop(p->data.filter.waiting_packets);
return(result);
}
static char *
put_filter(port *p,
string text,
int length)
{
string input;
string output;
if (p->status & INPUT_CLOSED)
return(NULL);
input = convert_nulls_to_newlines(text, length);
output = (*(p->data.filter.filter))(input);
free(input);
string_stack_push(p->data.filter.waiting_packets, output);
return(NULL);
}
static char *
close_filter_input(port *p)
{
while (!string_stack_empty(p->data.filter.waiting_packets))
string_stack_pop(p->data.filter.waiting_packets);
return(NULL);
}
/*ARGSUSED*/
static char *
close_filter_output(port *p)
{
return(NULL);
}
void
create_port_from_filter(string name,
string (*filter)(string))
{
port *p = create_named_port(name);
p->get = get_filter;
p->put = put_filter;
p->close_input = close_filter_input;
p->close_output = close_filter_output;
p->status = 0;
p->data.filter.waiting_packets = string_stack_create();
p->data.filter.filter = filter;
}
/****************************************************************************/
/* */
/* Code to implement a port given an output function: */
/* */
/****************************************************************************/
static char *
put_output(port *p,
string text,
int length)
{
string input;
char *error;
input = convert_nulls_to_newlines(text, length);
error = p->data.output.output(input);
free(input);
return(error);
}
/*ARGSUSED*/
static char *
close_output(port *p)
{
return(NULL);
}
void
create_port_from_output_proc(string name,
char *(*output)(string))
{
#ifdef SABER /* Yes, it's another ANSI incompatiblity */
port *p;
#else
port *p = create_named_port(name);
#endif
#ifdef SABER
p = create_named_port(name);
#endif
p->get = NULL;
p->put = put_output;
p->close_input = close_output;
p->close_output = close_output;
p->status = 0;
p->data.output.output = output;
}

124
zwgc/port.h Normal file
View File

@ -0,0 +1,124 @@
#ifndef port_TYPE
#define port_TYPE
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#include <stdio.h>
#include "new_string.h"
#include "string_stack.h"
union port__data {
struct {
FILE *input_connector;
FILE *output_connector;
} file;
struct {
string_stack waiting_packets;
string (*filter)(string);
} filter;
struct {
char *(*output)(string);
} output;
};
typedef struct port__struct { /* PRIVATE */
char *(*get)(struct port__struct *, char **);
char *(*put)(struct port__struct *, char *, int);
char *(*close_input)(struct port__struct *);
char *(*close_output)(struct port__struct *);
#define INPUT_CLOSED 0x1
#define OUTPUT_CLOSED 0x2
#define PORT_CLOSED 0x3
int status;
union port__data data;
} port;
/*
* void init_ports()
* Modifies: all ports
* Effects: Closes all existing ports. Must be called before
* any other port call is made.
*/
extern void init_ports(void);
/*
* string read_from_port(string name)
* Requires: init_ports has been called
* Modifies: the port named name if any, $error
* Effects: If a port by name name does not exist, sets $error to
* "No such port" & returns "". Otherwise, attempts to
* read from that port. If an error occurs, $error is
* set to the error message and "" returned. Otherwise
* the read string is returned. The returned string is
* on the heap & must be eventually freed.
*/
extern string read_from_port(string);
/*
* void write_on_port(string name, char *text, int length)
* Requires: init_ports has been called, length>=0
* Modifies: the port named name if any, $error
* Effects: If a port by name name does not exist, sets $error to
* "No such port" & returns. Otherwise, attempts to
* write text[0..length-1] on that port. If an error
* occurs, $error is set to the error message.
*/
extern void write_on_port(string, char *, int);
/*
* void close_port_input(string name)
* Requires: init_ports has been called
* Modifies: the port named name if any, $error
* Effects: If a port by name name does not exist, sets $error to
* "No such port" & returns. Otherwise, closes the
* input part of the port by name name. When both a
* port's input & output parts have been closed, the
* port is deleted to save space. If an error
* occurs, $error is set to the error message.
*/
extern void close_port_input(string);
/*
* void close_port_output(string name)
* Requires: init_ports has been called
* Modifies: the port named name if any, $error
* Effects: If a port by name name does not exist, sets $error to
* "No such port" & returns. Otherwise, closes the
* output part of the port by name name. When both a
* port's input & output parts have been closed, the
* port is deleted to save space. If an error
* occurs, $error is set to the error message.
*/
extern void close_port_output(string);
extern void create_subprocess_port(string, char **);
extern void create_file_append_port(string, string);
extern void create_file_input_port(string, string);
extern void create_file_output_port(string, string);
extern void create_port_from_filter(string, string (*)(string));
extern void create_port_from_output_proc(string, char *(*)(string));
extern void init_standard_ports(int *, char **);
extern void create_port_from_files(string, FILE *, FILE *);
#endif

46
zwgc/regexp.c Normal file
View File

@ -0,0 +1,46 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#include <regex.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_regexp_c[] = "$Id$";
#endif
#include "regexp.h"
int
ed_regexp_match_p(string test_string,
string pattern)
{
regex_t RE;
int retval;
char errbuf[512];
retval = regcomp(&RE, pattern, REG_NOSUB);
if (retval != 0) {
regerror(retval, &RE, errbuf, sizeof(errbuf));
fprintf(stderr,"%s in regcomp %s\n",errbuf,pattern);
return(0);
}
retval = regexec(&RE, test_string, 0, NULL, 0);
if (retval != 0 && retval != REG_NOMATCH) {
regerror(retval, &RE, errbuf, sizeof(errbuf));
fprintf(stderr,"%s in regexec %s\n",errbuf,pattern);
regfree(&RE);
return(0);
}
regfree(&RE);
return(retval == 0 ? 1 : 0);
}

24
zwgc/regexp.h Normal file
View File

@ -0,0 +1,24 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef regexp_MODULE
#define regexp_MODULE
#include "new_string.h"
extern int ed_regexp_match_p(string, string);
#endif

65
zwgc/stack.h Normal file
View File

@ -0,0 +1,65 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* A generic stack type based on linked lists: */
/* */
/****************************************************************************/
#ifndef TYPE_T_stack_TYPE
#define TYPE_T_stack_TYPE
#ifndef NULL
#define NULL 0
#endif
typedef struct _TYPE_T_stack {
struct _TYPE_T_stack *next;
TYPE_T data;
} *TYPE_T_stack;
#define TYPE_T_stack_create() ((struct _TYPE_T_stack *) NULL)
#define TYPE_T_stack_empty(stack) (!(stack))
#ifdef DEBUG
#define TYPE_T_stack_top(stack) ((stack) ? (stack)->data :\
(abort(),(stack)->data))
#else
#define TYPE_T_stack_top(stack) ((stack)->data)
#endif
#ifdef DEBUG
#define TYPE_T_stack_pop(stack) { TYPE_T_stack old = (stack);\
if (!old)\
abort(); /*<<<>>>*/\
(stack) = old->next;\
free(old); }
#else
#define TYPE_T_stack_pop(stack) { TYPE_T_stack old = (stack);\
(stack) = old->next;\
free(old); }
#endif
#define TYPE_T_stack_push(stack,object) \
{ TYPE_T_stack new = (struct _TYPE_T_stack *)\
malloc(sizeof (struct _TYPE_T_stack));\
new->next = (stack);\
new->data = object;\
(stack) = new; }
#endif

305
zwgc/standard_ports.c Normal file
View File

@ -0,0 +1,305 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_standard_ports_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* Code to setup standard ports: */
/* */
/****************************************************************************/
#include <zephyr/zephyr.h>
#include "new_memory.h"
#include "port.h"
#include "variables.h"
#include "error.h"
#include "main.h"
#include "tty_filter.h"
#ifndef X_DISPLAY_MISSING
#include "X_driver.h"
#endif
extern char *tty_filter(string, int);
extern int tty_filter_init(char *, char, int *, char **);
extern void usage(void);
/*
*
*/
static char *
plain_driver(string input)
{
string processed_input = tty_filter(input, 0);
fputs(processed_input, stdout);
fflush(stdout);
free(processed_input);
return(NULL);
}
/*
*
*/
static char *
tty_driver(string input)
{
string processed_input = tty_filter(input, 1);
fputs(processed_input, stdout);
fflush(stdout);
free(processed_input);
return(NULL);
}
/*
*
*/
static string
noop_filter(string input)
{
return(input);
}
/*
*
*/
static string
plain_filter(string input)
{
return(tty_filter(input, 0));
}
/*
*
*/
static string
fancy_filter(string input)
{
return(tty_filter(input, 1));
}
/*
*
*/
static struct standard_port_info {
char *port_name;
/*
* 0 = ok to use as the default output port
* 1 = not ok to use as the default output port
* 2 = disabled
*/
#define DEFAULT_OK 0
#define DEFAULT_NOTOK 1
#define DISABLED 2
int port_setup_status;
int (*port_init)(char *, char, int *, char **);
#define INPUT_DESC 0
#define OUTPUT_DESC 1
#define FILTER 2
#define OUTPUT_PROC 3
int type;
char *(*function)(string);
int setup_arg;
} standard_port_info_table[] = {
#ifndef X_DISPLAY_MISSING
{ "X", DEFAULT_OK, X_driver_init, OUTPUT_PROC, X_driver, 0},
{ "tty", DEFAULT_NOTOK, tty_filter_init, OUTPUT_PROC, tty_driver, 0},
#else
{ "tty", DEFAULT_OK, tty_filter_init, OUTPUT_PROC, tty_driver, 0},
#endif
{ "plain", DEFAULT_NOTOK, tty_filter_init, OUTPUT_PROC, plain_driver, 0},
{ "stdout", DEFAULT_NOTOK, NULL, OUTPUT_DESC, NULL, 1},
{ "stderr", DEFAULT_NOTOK, NULL, OUTPUT_DESC, NULL, 2},
{ "stdin", DEFAULT_NOTOK, NULL, INPUT_DESC, NULL, 0},
{ "loopback", DEFAULT_NOTOK, NULL, FILTER, noop_filter, 0},
{ "plain_filter", DEFAULT_NOTOK, tty_filter_init, FILTER, plain_filter, 0},
{ "tty_filter", DEFAULT_NOTOK, tty_filter_init, FILTER, fancy_filter, 0},
{ NULL, DISABLED, NULL, FILTER, NULL, 0} };
/*
* <<<>>>
*/
static struct standard_port_info *
get_standard_port_info(string port_name)
{
struct standard_port_info *p;
for (p=standard_port_info_table; p->port_name; p++)
if (string_Eq(p->port_name, port_name) && p->port_setup_status!=DISABLED)
return(p);
return(NULL);
}
/*
* Internal Routine:
*
* int boolean_value_of(string text)
* Effects: If text represents yes/true/on, return 1. If text
* representes no/false/off, return 0. Otherwise,
* returns -1.
*/
static int
boolean_value_of(string text)
{
if (!text)
return(-1); /* not set */
if (!strcasecmp("yes", text) || !strcasecmp("y", text) ||
!strcasecmp("true", text) || !strcasecmp("t", text) ||
!strcasecmp("on", text))
return(1);
else if (!strcasecmp("no", text) || !strcasecmp("n", text) ||
!strcasecmp("false", text) || !strcasecmp("f", text) ||
!strcasecmp("off", text))
return(0);
else
return(-1);
}
/*
*
*/
void init_standard_ports(int *pargc,
char **argv)
{
struct standard_port_info *p;
string first_working_port = "";
string default_port = "";
char **new, **current;
int fallback;
char *charset = NULL;
/*
* Process argument list handling "-disable <port>" and
* "-default <output port>" arguments, as well as "-ttymode"
* and -charset, because tty_filter_init gets run twice
*/
for (new=current=argv+1; *current; current++) {
if (string_Eq((string) *current, "-disable")) {
current++; *pargc -= 2;
if (!*current)
usage();
p = get_standard_port_info((string) *current);
if (p)
p->port_setup_status = DISABLED;
} else if (string_Eq((string) *current, "-default")) {
current++; *pargc -= 2;
if (!*current)
usage();
default_port = (string) *current;
p = get_standard_port_info((string) *current);
if (p)
p->port_setup_status = DEFAULT_OK;
} else if (string_Eq((string) *current, "-charset")) {
current++; *pargc -= 2;
if (!*current)
usage();
charset = *current;
} else if (string_Eq((string) *current, "-ttymode")) {
default_port = (string) "tty";
(*pargc)--;
p = get_standard_port_info(default_port);
if (p) {
p->port_setup_status = DEFAULT_OK;
p = get_standard_port_info ((string) "X");
if (p)
p->port_setup_status = DISABLED;
}
} else
*(new++) = *current;
}
*new = *current;
var_set_variable_then_free_value("tty_charset", (string)ZGetCharsetString(charset));
fallback = boolean_value_of(ZGetVariable("fallback"));
/*
* Initialize all non-disabled ports. If a port reports an error,
* disable that port. Set default_port if not already set
* by the -default argument to the first non-disabled port.
*/
for (p = standard_port_info_table; p->port_name; p++) {
if (p->port_setup_status == DISABLED)
continue;
if (p->port_init && (*(p->port_init))(p->port_name,
*first_working_port,
pargc, argv)) {
p->port_setup_status = DISABLED;
continue;
}
if (fallback == 1) {
/* we are doing fallback, make DEFAULT_NOTOK ports OK */
p->port_setup_status = DEFAULT_OK;
}
if (!*first_working_port)
first_working_port = p->port_name;
switch (p->type) {
case INPUT_DESC:
create_port_from_files(p->port_name, fdopen(p->setup_arg, "r"),0);
break;
case OUTPUT_DESC:
create_port_from_files(p->port_name, 0, fdopen(p->setup_arg, "w"));
break;
case FILTER:
create_port_from_filter(p->port_name, p->function);
break;
case OUTPUT_PROC:
create_port_from_output_proc(p->port_name, p->function);
break;
}
}
if (!default_port[0]) {
/* no default port has been set */
for (p = get_standard_port_info(first_working_port); p->port_name; p++)
if ((p->port_setup_status == DEFAULT_OK))
break;
if (p->port_name)
var_set_variable("output_driver", p->port_name);
else { /* no suitable default has been found */
if (fallback == -1) /* complain, since indeterminate */
ERROR2(
"To receive Zephyrgrams, (type `%s -ttymode').\n",
progname);
exit(1);
}
} else
var_set_variable("output_driver", default_port);
}

View File

@ -0,0 +1,102 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#if (!defined(lint) && !defined(SABER))
static const char rcsid_string_dictionary_aux_c[] = "$Id$";
#endif
/*
* string_dictionary_aux - a module implementing convenience routines for use
* with string_dictionarys
*
* Overview:
*
* This module implements Fetch and Set operations on
* string_dictionaries which take the place of Define and Lookup for
* most uses. The importance difference between them and Define and
* Lookup is that they maintain the invariant that all the value strings
* in a string_dictionary are on the heap. In particular, they do
* free's and string_Copy's whenever needed. Also implemented is
* SafeDestroy which does a Destroy after freeing all the value strings
* in a string_dictionary.
*/
#include <sysdep.h>
#include "new_memory.h"
#include "string_dictionary.h"
#include "string_dictionary_aux.h"
/*
* void string_dictionary_Set(string_dictionary d, string key,string value):
* Modifies: d
* Effects: Binds key to value in d. Automatically free's the
* previous value of key, if any. Value is copied on the
* heap.
*/
void
string__dictionary_Set(string_dictionary d,
string key,
string value)
{
string_dictionary_binding *binding;
int already_exists;
binding = string_dictionary_Define(d, key, &already_exists);
if (already_exists)
free(binding->value);
binding->value = string_Copy(value);
}
/*
* char *string_dictionary_Fetch(string_dictionary d, string key)
* Effects: If key is not bound in d, returns 0. Otherwise,
* returns the value that key is bound to.
* Note that the returned string if any should not be
* freed or modified in any way. Note also that it may
* disappear later if key is rebound.
*/
char *
string_dictionary_Fetch(string_dictionary d,
string key)
{
string_dictionary_binding *binding;
binding = string_dictionary_Lookup(d, key);
if (!binding)
return(0);
return(binding->value);
}
/*
* void string_dictionary_SafeDestroy(string_dictionary d)
* Modifies: d
* Effects: Like string_dictionary_Destroy except first frees
* all value's in the dictionary.
*/
static void
free_value_of_binding(string_dictionary_binding *b)
{
free(b->value);
}
void
string_dictionary_SafeDestroy(string_dictionary d)
{
string_dictionary_Enumerate(d, free_value_of_binding);
string_dictionary_Destroy(d);
}

View File

@ -0,0 +1,57 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#ifndef string_dictionary_aux_MODULE
#define string_dictionary_aux_MODULE
#include "new_memory.h"
#include "string_dictionary.h"
/*
* void string_dictionary_Set(string_dictionary d, string key,string value):
* Modifies: d
* Effects: Binds key to value in d. Automatically free's the
* previous value of key, if any. Value is copied on the
* heap.
*/
extern void string__dictionary_Set(string_dictionary, string, string);
#ifdef DEBUG_MEMORY
#define string_dictionary_Set(a,b,c) (set_module(__FILE__,__LINE__),\
string__dictionary_Set(a,b,c))
#else
#define string_dictionary_Set(a,b,c) string__dictionary_Set(a,b,c)
#endif
/*
* char *string_dictionary_Fetch(string_dictionary d, string key)
* Effects: If key is not bound in d, returns 0. Otherwise,
* returns the value that key is bound to.
* Note that the returned string if any should not be
* freed or modified in any way. Note also that it may
* disappear later if key is rebound.
*/
extern char *string_dictionary_Fetch(string_dictionary,
string);
/*
* void string_dictionary_SafeDestroy(string_dictionary d)
* Modifies: d
* Effects: Like string_dictionary_Destroy except first frees
* all value's in the dictionary.
*/
extern void string_dictionary_SafeDestroy(string_dictionary);
#endif

402
zwgc/subscriptions.c Normal file
View File

@ -0,0 +1,402 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#if (!defined(lint) && !defined(SABER))
static const char rcsid_subscriptions_c[] = "$Id$";
#endif
/****************************************************************************/
/* */
/* Subscriptions.c: code to deal with subscriptions & punting: */
/* */
/****************************************************************************/
#include <sysdep.h>
#include <zephyr/zephyr.h>
#include <netdb.h>
#include <arpa/nameser.h>
#include "new_memory.h"
#include "new_string.h"
#include "int_dictionary.h"
#include "zwgc.h"
#include "subscriptions.h"
#include "error.h"
#include "file.h"
#include "main.h"
/****************************************************************************/
/* */
/* Code to implement punting of notices: */
/* */
/****************************************************************************/
/*
*
*/
#ifndef CMU_ZCTL_PUNT
static
#endif
int_dictionary puntable_addresses_dict = 0;
static void
init_puntable_dict(void)
{
puntable_addresses_dict = int_dictionary_Create(33);
}
static string
address_to_string(string class,
string instance,
string recipient)
{
string result;
/*
* Treat a recipient of "" as "*":
*/
if (string_Eq(recipient,""))
recipient = "*";
else if (recipient[0] == '@') {
recipient = string_Concat("*", recipient);
}
/*
* The following is a hack for now only. It should be replaced with
* several calls to escape_code... <<<>>>
*/
result = string_Concat(class, "\001");
result = string_Concat2(result, instance);
result = string_Concat2(result, "\001");
result = string_Concat2(result, recipient);
string_Downcase(result);
return(result);
}
int puntable_address_p(string class,
string instance,
string recipient)
{
string temp;
if (!puntable_addresses_dict)
init_puntable_dict();
temp = address_to_string(class, instance, recipient);
if (int_dictionary_Lookup(puntable_addresses_dict, temp)) {
free(temp);
return 1;
}
free(temp);
/* This kludge is to allow punts of wildcard instance to work */
temp = address_to_string(class, "*", recipient);
if (int_dictionary_Lookup(puntable_addresses_dict, temp)) {
free(temp);
return(1);
}
free(temp);
return(0);
}
void punt(string class,
string instance,
string recipient)
{
string temp;
if (!puntable_addresses_dict)
init_puntable_dict();
temp = address_to_string(class, instance, recipient);
(void)int_dictionary_Define(puntable_addresses_dict, temp, 0);
free(temp);
}
void unpunt(string class,
string instance,
string recipient)
{
string temp;
int_dictionary_binding *binding;
if (!puntable_addresses_dict)
init_puntable_dict();
temp = address_to_string(class, instance, recipient);
binding = int_dictionary_Define(puntable_addresses_dict, temp, 0);
free(temp);
if (binding)
int_dictionary_Delete(puntable_addresses_dict, binding);
}
/****************************************************************************/
/* */
/* Code to implement batching [un]subscription requests: */
/* */
/****************************************************************************/
/*
* <<<>>> these routines require zwgc_active to be false (0)
*/
#define BATCH_SIZE 20
static int subscription_list_size = 0;
static ZSubscription_t subscription_list[BATCH_SIZE];
static int unsubscription_list_size = 0;
static ZSubscription_t unsubscription_list[BATCH_SIZE];
static void
free_subscription_list(ZSubscription_t *list,
int number_of_elements)
{
int i;
for (i=0; i<number_of_elements; i++) {
free(list[i].zsub_class);
free(list[i].zsub_classinst);
free(list[i].zsub_recipient);
}
}
static void
flush_subscriptions(void)
{
TRAP(ZSubscribeTo(subscription_list,subscription_list_size, 0),
"while subscribing");
free_subscription_list(subscription_list, subscription_list_size);
subscription_list_size = 0;
}
static void
flush_unsubscriptions(void)
{
if (unsubscription_list_size)
TRAP(ZUnsubscribeTo(unsubscription_list, unsubscription_list_size, 0),
"while unsubscribing");
free_subscription_list(unsubscription_list, unsubscription_list_size);
unsubscription_list_size = 0;
}
static void
subscribe(string class,
string instance,
string recipient)
{
subscription_list[subscription_list_size].zsub_class = string_Copy(class);
subscription_list[subscription_list_size].zsub_classinst= string_Copy(instance);
subscription_list[subscription_list_size].zsub_recipient=string_Copy(recipient);
if (++subscription_list_size == BATCH_SIZE)
flush_subscriptions();
}
static void
unsubscribe(string class,
string instance,
string recipient)
{
unsubscription_list[unsubscription_list_size].zsub_class = string_Copy(class);
unsubscription_list[unsubscription_list_size].zsub_classinst
= string_Copy(instance);
unsubscription_list[unsubscription_list_size].zsub_recipient
= string_Copy(recipient);
if (++unsubscription_list_size == BATCH_SIZE)
flush_unsubscriptions();
}
/****************************************************************************/
/* */
/* Code to implement reading [un]subscriptions from a file: */
/* */
/****************************************************************************/
#define TOKEN_HOSTNAME "%host%"
#define TOKEN_CANONNAME "%canon%"
#define TOKEN_ME "%me%"
#define TOKEN_WILD "*"
char ourhost[NS_MAXDNAME], ourhostcanon[NS_MAXDNAME];
static void
inithosts(void)
{
struct hostent *hent;
if (gethostname(ourhost, sizeof(ourhost)-1) == -1) {
ERROR3("unable to retrieve hostname, %s and %s will be wrong in subscriptions.\n", TOKEN_HOSTNAME, TOKEN_CANONNAME);
return;
}
if (!(hent = gethostbyname(ourhost))) {
ERROR2("unable to resolve hostname, %s will be wrong in subscriptions.\n", TOKEN_CANONNAME);
strncpy(ourhostcanon, ourhost, sizeof(ourhostcanon)-1);
return;
}
strncpy(ourhostcanon, hent->h_name, sizeof(ourhostcanon)-1);
return;
}
static void
macro_sub(char *str)
{
static int initedhosts = 0;
if (!initedhosts) {
inithosts();
initedhosts = 1;
}
if (string_Eq(str, TOKEN_ME))
strcpy(str, ZGetSender());
else if (string_Eq(str, TOKEN_HOSTNAME))
strcpy(str, ourhost);
else if (string_Eq(str, TOKEN_CANONNAME))
strcpy(str, ourhostcanon);
}
#define UNSUBSCRIBE_CHARACTER '!'
#define PUNT_CHARACTER '-'
static void
load_subscriptions_from_file(FILE *file)
{
char line[BUFSIZ];
char class_buffer[BUFSIZ], instance[BUFSIZ], recipient[BUFSIZ];
char *class, *temp;
char c;
while ((!feof(file)) && (!ferror(file))) {
if (fgets(line, BUFSIZ, file)) {
class = class_buffer;
/* Parse line */
/* <<<>>>
* The below does NOT work is the recipient field is "":
*/
temp = strchr(line, '#');
if (temp)
*temp = '\0';
for (temp=line; *temp && *temp==' '; temp++) ;
if (!*temp || *temp=='\n')
continue;
sscanf(temp,"%[^,],%[^,],%s", class, instance, recipient);
/* skip type indicator if any: */
c = class[0];
if (c==UNSUBSCRIBE_CHARACTER || c==PUNT_CHARACTER)
class++;
/* perform macro substitutions */
macro_sub(class);
macro_sub(instance);
macro_sub(recipient);
/* do the right thing with it */
switch (c) {
case UNSUBSCRIBE_CHARACTER:
unsubscribe(class, instance, recipient);
break;
case PUNT_CHARACTER:
punt(class, instance, recipient);
break;
default:
subscribe(class, instance, recipient);
break;
}
} else {
break;
}
}
if (ferror(file)) {
com_err("zwgc", errno, "while reading from subscription file");
exit(1);
}
flush_subscriptions();
flush_unsubscriptions();
fclose(file);
}
#define DEFSUBS "/dev/null"
static void
load_subscriptions(void)
{
FILE *subscriptions_file;
/* no system default sub file on client--they live on the server */
/* BUT...we need to use something to call load_subscriptions_from_file,
so we use /dev/null */
subscriptions_file = locate_file(subscriptions_filename_override,
USRSUBS, DEFSUBS);
if (subscriptions_file)
load_subscriptions_from_file(subscriptions_file);
}
/****************************************************************************/
/* */
/* Code to implement shutdown and startup: */
/* */
/****************************************************************************/
int zwgc_active = 0;
static ZSubscription_t *saved_subscriptions = NULL;
static int number_of_saved_subscriptions;
void zwgc_shutdown(void)
{
if (!zwgc_active)
return;
TRAP(ZRetrieveSubscriptions(0, &number_of_saved_subscriptions),
"while retrieving zephyr subscription list");
if (error_code)
return;
saved_subscriptions = (ZSubscription_t *)
malloc(number_of_saved_subscriptions*sizeof(ZSubscription_t));
if (number_of_saved_subscriptions)
TRAP(ZGetSubscriptions(saved_subscriptions,
&number_of_saved_subscriptions),
"while getting subscriptions");
if (error_code) {
free(saved_subscriptions);
saved_subscriptions = NULL;
}
TRAP(ZCancelSubscriptions(0), "while canceling subscriptions") ;
zwgc_active = 0;
}
void zwgc_startup(void)
{
if (zwgc_active)
return;
if (saved_subscriptions) {
TRAP(ZSubscribeToSansDefaults(saved_subscriptions,number_of_saved_subscriptions,0),
"while resubscribing to zephyr messages");
free(saved_subscriptions);
saved_subscriptions = NULL;
} else
load_subscriptions();
zwgc_active = 1;
}

30
zwgc/subscriptions.h Normal file
View File

@ -0,0 +1,30 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef subscriptions_MODULE
#define subscriptions_MODULE
extern int zwgc_active;
extern int puntable_address_p(string, string, string);
extern void punt(string, string, string);
extern void unpunt(string, string, string);
extern void zwgc_shutdown(void);
extern void zwgc_startup(void);
#define USRSUBS ".zephyr.subs"
#endif

169
zwgc/substitute.c Normal file
View File

@ -0,0 +1,169 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#if (!defined(lint) && !defined(SABER))
static const char rcsid_substitute_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
#include <sysdep.h>
#include "new_memory.h"
#include "lexer.h"
#include "substitute.h"
/*
* Internal Routine:
*
* string eat_dollar_sign_stuff(string (*lookup)(string); string *text_ptr)
* Modifies: *text_ptr
* Effects: This routine deals with handling the stuff after a '$'
* for substitute. If *text_ptr starts with a valid
* variable reference (minus the leading '$'), we look up
* the variable using lookup and return its value.
* *text_ptr is also advanced past the variable reference.
* If a '$' starts *text_ptr, *text_ptr is advanced past it &
* "$" returned. (This handles "$$" -> "$") Otherwise,
* "$" is returned and *text_ptr is not advanced.
* The returned string must not be freed.
*/
static string
eat_dollar_sign_stuff(string (*lookup)(string),
string *text_ptr) /* Input/Output parameter */
{
char c;
char closing_brace = 0;
char *p = *text_ptr;
char *variable_name_start;
int variable_name_length;
/*
* Handle "$$" -> "$" translation:
*/
c = *p;
if (c=='$') {
*text_ptr = p+1;
return("$");
}
/*
* If opening brace present (i.e., '(' or '{'), skip it and save away
* what closing brace we must see at the end of the variable reference:
*/
if (c=='{') {
closing_brace = '}';
c = *++p;
} else if (c=='(') {
closing_brace = ')';
c = *++p;
}
/*
* Eat {identifier_char}* keeping track of what we ate:
*/
variable_name_start = p;
variable_name_length = 0;
while (c = *p, is_identifier_char(c)) {
p++;
variable_name_length++;
}
/*
* If there was an opening brace, there had better be a comparable
* closing brace. If so, skip it. If not, we have an invalid variable
* reference so return '$' without advancing *text_ptr.
*/
if (closing_brace) {
if (c==closing_brace)
c = *++p;
else
return("$");
}
/*
* Zero length variable names are not valid:
*/
if (!variable_name_length)
return("$");
/*
* We have a valid variable reference. Advance past it then lookup
* its value and return it:
*/
*text_ptr = p;
if (variable_name_length > MAX_IDENTIFIER_LENGTH)
variable_name_length = MAX_IDENTIFIER_LENGTH;
variable_name_start = string_CreateFromData(variable_name_start,
variable_name_length);
p = lookup(variable_name_start);
free(variable_name_start);
return(p);
}
/*
* string substitute(string (*lookup)(string); string text)
* Effects: returns the result of expanding all variable
* references in text using lookup. Example:
* "test $foo.$bar baz" would be translated to
* "text <foo>.<bar> baz" where "<foo>" is the value of
* lookup("foo") and "<bar>" is the value of lookup("bar").
* Variables are case sensitive and have the form
* {identifier_char}+ where identifier_char is defined
* in lexer.h by is_identifier_char. $(foo) and
* ${foo} are alternate forms for $foo. In particular,
* ${foo}bar is a reference to foo followed by "bar" while
* $foobar is a reference to foobar. Incomplete variable
* references like $(foo bar are displayed as if they
* were not variable references. To allow quoting, "$$"
* is translated to "$". Only the first
* MAX_IDENTIFIER_LENGTH characters of an identifier are
* significant. The strings returned by lookup are not
* modified in any way or freed.
*/
string
substitute(string (*lookup)(string),
string text)
{
string result_so_far = string_Copy("");
char *p, *temp;
for (;;) {
/*
* Move [^$]* from start of text to end of result_so_far:
*/
for (p=text; *p && (*p)!='$'; p++) ;
if (text != p) {
temp = string_CreateFromData(text, p-text);
text = p;
result_so_far = string_Concat2(result_so_far, temp);
free(temp);
}
/*
* If text now empty, exit -- the result is in result_so_far:
*/
if (!*text)
return(result_so_far);
/*
* Otherwise, text begins with a '$'. Eat it then call
* eat_dollar_sign_stuff to process stuff after it.
* Append result to result_so_far, update text, & continue.
*/
text++;
p = eat_dollar_sign_stuff(lookup, &text);
result_so_far = string_Concat2(result_so_far, p);
}
}

45
zwgc/substitute.h Normal file
View File

@ -0,0 +1,45 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef substitute_MODULE
#define substitute_MODULE
#include "new_string.h"
/*
* string substitute(string (*lookup)(string); string text)
* Effects: returns the result of expanding all variable
* references in text using lookup. Example:
* "test $foo.$bar baz" would be translated to
* "text <foo>.<bar> baz" where "<foo>" is the value of
* lookup("foo") and "<bar>" is the value of lookup("bar").
* Variables are case sensitive and have the form
* {identifier_char}+ where identifier_char is defined
* in lexer.h by is_identifier_char. $(foo) and
* ${foo} are alternate forms for $foo. In particular,
* ${foo}bar is a reference to foo followed by "bar" while
* $foobar is a reference to foobar. Incomplete variable
* references like $(foo bar are displayed as if they
* were not variable references. To allow quoting, "$$"
* is translated to "$". Only the first
* MAX_IDENTIFIER_LENGTH characters of an identifier are
* significant. The strings returned by lookup are not
* modified in any way or freed.
*/
extern string substitute(string (*)(string), string);
#endif

129
zwgc/text_operations.c Normal file
View File

@ -0,0 +1,129 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_text_operations_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
#include "new_memory.h"
#include "text_operations.h"
#include "char_stack.h"
string
lany(string *text_ptr,
string str)
{
string result, whats_left;
char *p = *text_ptr;
while (*p && *str) p++, str++;
result = string_CreateFromData(*text_ptr, p - *text_ptr);
whats_left = string_Copy(p);
free(*text_ptr);
*text_ptr = whats_left;
return(result);
}
string
lbreak(string *text_ptr,
const character_class set)
{
string result, whats_left;
char *p = *text_ptr;
while (*p && !set[(int)*p]) p++;
result = string_CreateFromData(*text_ptr, p - *text_ptr);
whats_left = string_Copy(p);
free(*text_ptr);
*text_ptr = whats_left;
return(result);
}
string
lspan(string *text_ptr,
character_class set)
{
string result, whats_left;
char *p = *text_ptr;
while (*p && set[(int)*p]) p++;
result = string_CreateFromData(*text_ptr, p - *text_ptr);
whats_left = string_Copy(p);
free(*text_ptr);
*text_ptr = whats_left;
return(result);
}
string
rany(string *text_ptr,
string str)
{
string result, whats_left;
string text = *text_ptr;
char *p = text + strlen(text);
while (text<p && *str) p--, str++;
result = string_Copy(p);
whats_left = string_CreateFromData(text, p - text);
free(text);
*text_ptr = whats_left;
return(result);
}
string
rbreak(string *text_ptr,
character_class set)
{
string result, whats_left;
string text = *text_ptr;
char *p = text + strlen(text);
while (text<p && !set[(int)p[-1]]) p--;
result = string_Copy(p);
whats_left = string_CreateFromData(text, p - text);
free(text);
*text_ptr = whats_left;
return(result);
}
string
rspan(string *text_ptr,
character_class set)
{
string result, whats_left;
string text = *text_ptr;
char *p = text + strlen(text);
while (text<p && set[(int)p[-1]]) p--;
result = string_Copy(p);
whats_left = string_CreateFromData(text, p - text);
free(text);
*text_ptr = whats_left;
return(result);
}

29
zwgc/text_operations.h Normal file
View File

@ -0,0 +1,29 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef text_operations_MODULE
#define text_operations_MODULE
#include "character_class.h"
extern string lany(string *, string);
extern string lbreak(string *, const character_class);
extern string lspan(string *, character_class);
extern string rany(string *, string);
extern string rbreak(string *, character_class);
extern string rspan(string *, character_class);
#endif

597
zwgc/tty_filter.c Normal file
View File

@ -0,0 +1,597 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_tty_filter_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* The tty & plain filters: */
/* */
/****************************************************************************/
#ifdef HAVE_TERMCAP_H
#include <termcap.h>
#else
#ifdef HAVE_TERM_H
#ifdef HAVE_TERMIO_H
/* I blame Solaris. Solaris to blame. */
#include <termio.h>
#endif
#ifdef HAVE_CURSES_H
#include <curses.h>
#endif
#include <term.h>
#endif
#endif
#include <zephyr/zephyr.h>
#include "new_memory.h"
#include "new_string.h"
#include "variables.h"
#include "string_dictionary_aux.h"
#include "formatter.h"
#include "zwgc.h"
#include "error.h"
#include "tty_filter.h"
/***************************************************************************/
#ifndef HAVE_TERMCAP_H
extern int tgetent();
extern char *tgetstr(),*getenv();
#ifdef linux
extern speed_t ospeed;
#else
extern short ospeed;
#endif
char PC;
#endif
/* Dictionary naming convention:
B.xxx is the termcap sequence to begin environment xxx.
E.xxx is the termcap sequence to end environment xxx.
*/
static string_dictionary termcap_dict;
static char code_buf[10240], *code_buf_pos = code_buf, *code;
/* Define the following commands:
(Hopefully) shared with all devices:
@center Guess.
@em Emphasis. User underline if available, else reverse video.
@bold Bold letters. If not available, reverse video, else underline.
@beep "bl" termcap entry, else "^G"
Other:
@blink "mb"/"me" termcap entry, else nothing.
@rv "so"/"se" termcap entry.
@u "us"/"ue" termcap entry.
*/
#define TD_SET(k,v) (string_dictionary_Define(termcap_dict, (k), &ex)->value \
= (v))
#define EXPAND(k) (code = code_buf_pos, tputs(tmp, 1, tty_outc), \
*code_buf_pos++ = 0, TD_SET(k, code))
static int
tty_outc(int c)
{
*code_buf_pos++ = c;
return 0;
}
/* ARGSUSED */
int
tty_filter_init(char *drivername,
char notfirst,
int *pargc,
char **argv)
{
static char st_buf[128];
char tc_buf[1024], *p = st_buf, *tmp, *term;
int ex;
string_dictionary_binding *b;
int isrealtty = string_Eq(drivername, "tty");
struct termios tbuf;
ospeed = (tcgetattr(STDIN_FILENO, &tbuf) == 0) ? cfgetospeed(&tbuf) : 2400;
if (termcap_dict == (string_dictionary) NULL)
termcap_dict = string_dictionary_Create(7);
if (!(term = getenv("TERM"))) { /* Only use termcap if $TERM. */
if (isrealtty && !notfirst)
/* only complain if initializing tty mode, and would be first
available port */
ERROR("$TERM not set. tty mode will be plain.\n");
}
#ifdef _AIX
/*
* This is a temporary KLUDGE to get around the problem where some people
* might start zwgc in their ~/.startup.X and it hangs on the RISC/6000.
* Apparently, the call to tgetent() with the Athena console window causes
* the process to get stopped on tty access. Since the terminal type is
* "dumb" (set by tcsh), we can pretty much assume there isn't anything
* to setup from the termcap information.
*/
else if (!strcmp(term, "dumb")) { }
#endif
else {
tgetent(tc_buf, term);
/* Step 1: get all of {rv,bold,u,bell,blink} that are available. */
/* We cheat here, and ignore the padding (if any) specified for
the mode-change strings (it's a real pain to do "right") */
tmp = tgetstr("pc", &p);
PC = (tmp) ? *tmp : 0;
tmp = tgetstr("md", &p);
if (tmp) { /* bold ? */
EXPAND("B.bold");
tmp = tgetstr("me",&p);
EXPAND("E.bold");
}
tmp = tgetstr("mr", &p);
if (tmp) { /* reverse video? */
EXPAND("B.rw");
tmp = tgetstr("me", &p);
EXPAND("E.rw");
}
tmp = tgetstr("bl", &p);
if (tmp) { /* Bell ? */
EXPAND("B.bell");
TD_SET("E.bell", NULL);
}
tmp = tgetstr("mb", &p);
if (tmp) { /* Blink ? */
EXPAND("B.blink");
tmp = tgetstr("me", &p);
EXPAND("E.blink");
}
tmp = tgetstr("us", &p);
if (tmp) { /* Underline ? */
EXPAND("B.u");
tmp = tgetstr("ue", &p);
EXPAND("E.u");
}
tmp = tgetstr("so", &p);
if (tmp) { /* Standout ? */
EXPAND("B.so");
tmp = tgetstr("se", &p);
EXPAND("E.so");
}
}
/* Step 2: alias others to the nearest substitute */
/* Bold = so, else rv, else ul */
if (NULL == string_dictionary_Lookup(termcap_dict, "B.bold")) {
if((b = string_dictionary_Lookup(termcap_dict, "B.so"))) {
TD_SET("B.bold", b->value);
TD_SET("E.bold",
string_dictionary_Lookup(termcap_dict, "E.so")->value);
} else if ((b = string_dictionary_Lookup(termcap_dict, "B.rv"))) {
TD_SET("B.bold", b->value);
TD_SET("E.bold",
string_dictionary_Lookup(termcap_dict, "E.rv")->value);
} else if ((b = string_dictionary_Lookup(termcap_dict,"B.u"))) {
TD_SET("B.bold", b->value);
TD_SET("E.bold",
string_dictionary_Lookup(termcap_dict, "E.u")->value);
}
}
/* Bell = ^G */
if (NULL == string_dictionary_Lookup(termcap_dict, "B.bell")) {
TD_SET("B.bell", "\007");
TD_SET("E.bell", NULL);
}
/* Underline -> nothing */
/* Blink -> nothing */
return(0);
}
/***************************************************************************/
static int
fixed_string_eq(string pattern,
char *text,
int text_length)
{
while (*pattern && text_length>0 && *pattern == *text) {
pattern++;
text++;
text_length--;
}
return(!*pattern && !text_length);
}
typedef struct _tty_str_info {
struct _tty_str_info *next;
char *str;
int len;
char alignment; /* 'l', 'c', 'r', or ' ' to indicate newline */
unsigned int bold_p : 1;
unsigned int italic_p : 1;
unsigned int bell_p : 1;
unsigned int ignore: 1;
} tty_str_info;
const char *info_default_string = "";
static void
free_info(tty_str_info *info)
{
tty_str_info *next_info;
while (info) {
next_info = info->next;
if (info->str != info_default_string)
free(info->str);
free(info);
info = next_info;
}
}
static int
do_mode_change(tty_str_info *current_mode_p,
char *text,
int text_length)
{
/* alignment commands: */
if (fixed_string_eq("left", text, text_length) ||
fixed_string_eq("l", text, text_length))
current_mode_p->alignment = 'l';
else if (fixed_string_eq("center", text, text_length) ||
fixed_string_eq("c", text, text_length))
current_mode_p->alignment = 'c';
else if (fixed_string_eq("right", text, text_length) ||
fixed_string_eq("r", text, text_length))
current_mode_p->alignment = 'r';
/* font commands: */
else if (fixed_string_eq("bold", text, text_length) ||
fixed_string_eq("b", text, text_length))
current_mode_p->bold_p = 1;
else if (fixed_string_eq("italic", text, text_length) ||
fixed_string_eq("i", text, text_length))
current_mode_p->italic_p = 1;
else if (fixed_string_eq("roman", text, text_length)) {
current_mode_p->bold_p = 0;
current_mode_p->italic_p = 0;
} else if (fixed_string_eq("beep", text, text_length)) {
current_mode_p->bell_p = 1;
return 1;
}
/* commands ignored in tty mode: */
else if (fixed_string_eq("color", text, text_length) ||
fixed_string_eq("font", text, text_length)) {
current_mode_p->ignore = 1;
}
return 0;
}
static void
zwgc_transliterate(char *in, int inlen, char **out, int *outlen){
int retval = 0;
string notice_charset = var_get_variable("notice_charset");
string tty_charset = var_get_variable("tty_charset");
if (string_Eq(notice_charset, "UNKNOWN") ||
string_Eq(notice_charset, tty_charset) ||
(retval = ZTransliterate(in, inlen,
notice_charset, tty_charset,
out, outlen)) != 0) {
*out = string_CreateFromData(in, inlen);
*outlen = inlen;
}
if (retval != 0)
var_set_variable("error", strerror(retval));
}
static tty_str_info *
convert_desc_to_tty_str_info(desctype *desc)
{
tty_str_info *temp;
tty_str_info *result = NULL;
tty_str_info *last_result_block = NULL;
int isbeep, did_beep = 0;
#if !defined(SABER) && defined(__STDC__)
tty_str_info current_mode = { NULL, "", 0, 'l', 0 , 0, 0, 0};
#else
/* This is needed due to a bug in saber, and lack of pre-ANSI support. */
tty_str_info current_mode;
current_mode.next = NULL;
current_mode.str = info_default_string; /* "" */
current_mode.len = 0;
current_mode.alignment = 'l';
current_mode.bold_p = 0;
current_mode.italic_p = 0;
current_mode.bell_p = 0;
current_mode.ignore = 0;
#endif
for (; desc->code!=DT_EOF; desc=desc->next) {
isbeep = 0;
/* Handle environments: */
if (desc->code == DT_ENV) {
/* PUSH! */
temp = (tty_str_info *)malloc(sizeof(struct _tty_str_info));
*temp = current_mode;
current_mode.next = temp;
isbeep = do_mode_change(&current_mode, desc->str, desc->len);
if (!isbeep || did_beep)
continue; /* process one beep, ignore other envs */
} else if (desc->code == DT_END) {
/* POP! */
temp = current_mode.next;
current_mode = *temp;
free(temp);
continue;
}
/* Add new block (call it temp) to result: */
temp = (tty_str_info *)malloc(sizeof(struct _tty_str_info));
*temp = current_mode;
if (last_result_block) {
last_result_block->next = temp;
last_result_block = temp;
} else {
result = temp;
last_result_block = temp;
}
if (isbeep) {
/* special processing: need to insert a bell */
string_dictionary_binding *b;
b = string_dictionary_Lookup(termcap_dict,"B.bell");
if (b) {
temp->str = strdup(b->value);
temp->len = string_Length(temp->str);
} else
/* shouldn't get here! */
abort();
did_beep++;
continue;
}
if (desc->code == DT_STR) {
/* just combine string info with current mode: */
zwgc_transliterate(desc->str, desc->len, &temp->str, &temp->len);
} else if (desc->code == DT_NL) {
/* make the new block a ' ' alignment block with an empty string */
temp->alignment = ' ';
temp->len = 0;
temp->ignore = 0;
}
}
if (last_result_block)
last_result_block->next = NULL;
return(result);
}
#define max(a,b) ((a)>(b)?(a):(b))
static int
line_width(int left_width,
int center_width,
int right_width)
{
if (center_width>0) {
if (left_width==0 && right_width==0)
return(center_width);
return(center_width+2+max(left_width,right_width)*2);
} else {
if (left_width && right_width)
return(1+left_width+right_width);
else
return(left_width+right_width);
}
}
static int
calc_max_line_width(tty_str_info *info)
{
int max_line_width = 0;
int left = 0;
int center = 0;
int right = 0;
for (; info; info=info->next) {
if (info->ignore)
continue;
switch (info->alignment) {
case 'l':
left += info->len;
break;
case 'c':
center += info->len;
break;
case 'r':
right += info->len;
break;
case ' ':
#ifdef DEBUG
if (zwgc_debug)
printf("width: %d %d %d = %d\n", left, center, right,
line_width(left, center, right));
#endif
max_line_width = max(max_line_width,
line_width(left, center, right));
left = center = right = 0;
break;
}
}
#ifdef DEBUG
if (zwgc_debug)
printf("width: %d %d %d = %d\n", left, center, right,
line_width(left, center, right));
#endif
max_line_width = max(max_line_width,
line_width(left, center, right));
return(max_line_width);
}
string
tty_filter(string text,
int use_fonts)
{
string text_copy = string_Copy(text);
string result_so_far = string_Copy("");
desctype *desc;
int number_of_strs;
int number_of_lines;
tty_str_info *info, *info_head;
int max_line_width;
desc = disp_get_cmds(text_copy, &number_of_strs, &number_of_lines);
info_head = info = convert_desc_to_tty_str_info(desc);
free_desc(desc);
#ifdef DEBUG
if (zwgc_debug)
{ tty_str_info *ptr;
for (ptr=info; ptr; ptr=ptr->next) {
printf("%c: %s %s %s <%s>\n", ptr->alignment,
ptr->bold_p ? "(bold)" : "",
ptr->italic_p ? "(italic)" : "",
ptr->bell_p ? "(bell)" : "",
string_CreateFromData(ptr->str, ptr->len));
}
}
#endif
max_line_width = calc_max_line_width(info);
dprintf1("max width = %d\n", max_line_width);
while (info) {
string left, center, right;
int left_width, center_width, right_width;
char *temp;
left_width = center_width = right_width = 0;
left = string_Copy("");
center = string_Copy("");
right = string_Copy("");
for (; info && info->alignment!=' '; info=info->next) {
string item;
if (info->ignore)
continue;
item = string_Copy("");
if (info->bold_p && use_fonts) {
temp = string_dictionary_Fetch(termcap_dict, "B.bold");
if (temp)
item = string_Concat2(item, temp);
} else if (info->italic_p && use_fonts) {
temp = string_dictionary_Fetch(termcap_dict, "B.u");
if (temp)
item = string_Concat2(item, temp);
}
temp = string_CreateFromData(info->str, info->len);
item = string_Concat2(item, temp);
free(temp);
if (info->bold_p && use_fonts) {
temp = string_dictionary_Fetch(termcap_dict, "E.bold");
if (temp)
item = string_Concat2(item, temp);
} else if (info->italic_p && use_fonts) {
temp = string_dictionary_Fetch(termcap_dict, "E.u");
if (temp)
item = string_Concat2(item, temp);
}
switch (info->alignment) {
default:
case 'l':
left = string_Concat2(left, item);
left_width += info->len;
break;
case 'c':
center = string_Concat2(center, item);
center_width += info->len;
break;
case 'r':
right = string_Concat2(right, item);
right_width += info->len;
break;
}
free(item);
}
result_so_far = string_Concat2(result_so_far, left);
if (center_width)
while (left_width < (max_line_width-center_width)/2 ) {
result_so_far = string_Concat2(result_so_far, " ");
left_width++;
}
result_so_far = string_Concat2(result_so_far, center);
left_width += center_width;
if (right_width)
while (left_width<max_line_width-right_width) {
result_so_far = string_Concat2(result_so_far, " ");
left_width++;
}
result_so_far = string_Concat2(result_so_far, right);
free(left); free(center); free(right);
if (info && info->alignment == ' ') {
info = info->next;
result_so_far = string_Concat2(result_so_far, "\r\n");
}
}
free_info(info_head);
free(text_copy);
if (number_of_lines &&
(result_so_far[string_Length(result_so_far)-1] != '\n'))
/* CRLF-terminate all results */
result_so_far = string_Concat2(result_so_far, "\r\n");
return(result_so_far);
}

2
zwgc/tty_filter.h Normal file
View File

@ -0,0 +1,2 @@
extern int tty_filter_init(char *, char, int *, char **);
extern string tty_filter(string, int);

4
zwgc/unsigned_long.h Normal file
View File

@ -0,0 +1,4 @@
/* $Id$
*/
#define unsigned_long unsigned long

243
zwgc/variables.c Normal file
View File

@ -0,0 +1,243 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_variables_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* Module containing code to deal with description langauge variables: */
/* */
/****************************************************************************/
#include "new_memory.h"
#include "notice.h"
#include "string_dictionary_aux.h"
#include "variables.h"
/*
* fields_data[_length] - these point to the field data that the number
* variables were last set to using
* var_set_number_variables_to_fields.
*/
static char *fields_data;
static int fields_data_length = 0;
/*
* [non_]number_variable_dict - contains the values of all the [non-]number
* variables that have been set since the last
* var_clear_all_variables call or (for numbers
* only) var_set_number_variables_to_fields call.
*/
static string_dictionary non_number_variable_dict = NULL;
static string_dictionary number_variable_dict = NULL;
/*
* Internal Routine:
*
* int is_digits(string text)
* Effects: Returns true iff text matches [0-9]*. ("" matches...)
*/
static int
is_digits(string text)
{
for (; *text; text++)
if (!isdigit(*text))
return(0);
return(1);
}
/*
* Internal Routine:
*
* int is_number_variable(string text)
* Effects: Returns true iff text matches [0-9]+.
*/
#define is_number_variable(x) (isdigit(*(x)) && is_digits((x)))
/*
* void var_clear_all_variables()
* Requires: This routine must be called before any other
* var module routine is called.
* Modifies: All description language variables
* Effects: Sets all description langauge variables to "".
*/
void
var_clear_all_variables(void)
{
if (non_number_variable_dict) {
string_dictionary_SafeDestroy(non_number_variable_dict);
string_dictionary_SafeDestroy(number_variable_dict);
}
non_number_variable_dict = string_dictionary_Create(101);
number_variable_dict = string_dictionary_Create(11);
fields_data_length = 0;
}
/*
* string var_get_variable(string name)
* Requires: var_clear_all_variables has been called
* Effects: Returns the value of the description langauge variable
* named name. The returned string is read-only and is
* guarenteed to last only until the next var module
* call. DO NOT FREE THIS STRING.
*/
string
var_get_variable(string name)
{
char *result;
int field_to_get;
static string last_get_field_call_result = NULL;
if (is_number_variable(name)) {
result = string_dictionary_Fetch(number_variable_dict, name);
if (result)
return(result);
/*
* Convert name to an integer avoiding overflow:
*/
while (*name=='0')
name++;
if (strlen(name)>12)
field_to_get = 0; /* no way we'll have > 1 trillian fields... */
else
field_to_get = atoi(name);
if (!field_to_get)
return("");
if (last_get_field_call_result)
free(last_get_field_call_result);
last_get_field_call_result = get_field(fields_data,
fields_data_length,
field_to_get);
return(last_get_field_call_result);
}
if (!(result = string_dictionary_Fetch(non_number_variable_dict, name)))
result = "";
return(result);
}
/*
* void var_set_variable(string name, value)
* Requires: var_clear_all_variables has been called
* Modifies: The value of description langauge variable
* named name.
* Effects: Sets the description langauge variable named name
* to have the value value.
*/
void
var_set_variable(string name,
string value)
{
string_dictionary_Set(is_number_variable(name) ? number_variable_dict
: non_number_variable_dict, name, value);
}
/*
* void var_set_variable_to_number(string name; int number)
* Requires: var_clear_all_variables has been called
* Modifies: The value of description langauge variable
* named name.
* Effects: Sets the description langauge variable named name
* to have as its value number's ascii representation.
*/
void
var_set_variable_to_number(string name,
int number)
{
char buffer[20];
sprintf(buffer, "%d", number);
var_set_variable(name, buffer);
}
/*
* void var_set_variable_then_free_value(string name, value)
* Requires: var_clear_all_variables has been called, value is
* on the heap.
* Modifies: The value of description langauge variable
* named name, value
* Effects: Sets the description langauge variable named name
* to have the value value then frees value. This
* routine is slightly faster than calling var_set_variable
* then freeing value. It is provided mainly for
* convenience reasons.
*/
void
var_set_variable_then_free_value(string name,
string value)
{
string_dictionary_binding *binding;
int exists;
#ifdef DEBUG_MEMORY
if (!memory__on_heap_p(value))
abort(); /* <<<>>> */
#endif
if (is_number_variable(name)) {
var_set_variable(name, value);
free(value);
return;
}
binding = string_dictionary_Define(non_number_variable_dict, name,
&exists);
if (exists)
free(binding->value);
binding->value = value;
}
/*
* void var_set_number_variables_to_fields(char *data, int length)
* Requires: var_clear_all_variables has been called
* Modifies: All numeric description language variables
* Effects: Treats data[0]..data[length-1] as a series of
* null-seperated fields. Sets $<number> (<number>
* here means [0-9]+ to field # <number> in data.
* Field 0 is defined to be "" as are all field #'s
* greater than the number of fields in data.
* Data[0]..data[length-1] must not be changed (or freed)
* until either this call is made again with different
* data or var_clear_all_variables is called.
*/
void
var_set_number_variables_to_fields(char *data,
int length)
{
fields_data = data;
fields_data_length = length;
string_dictionary_SafeDestroy(number_variable_dict);
number_variable_dict = string_dictionary_Create(11);
}

96
zwgc/variables.h Normal file
View File

@ -0,0 +1,96 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef var_MODULE
#define var_MODULE
#include "new_string.h"
/*
* void var_clear_all_variables()
* Requires: This routine must be called before any other
* var module routine is called.
* Modifies: All description language variables
* Effects: Sets all description langauge variables to "".
*/
extern void var_clear_all_variables(void);
/*
* string var_get_variable(string name)
* Requires: var_clear_all_variables has been called
* Effects: Returns the value of the description langauge variable
* named name. The returned string is read-only and is
* guarenteed to last only until the next var module
* call. DO NOT FREE THIS STRING.
*/
extern string var_get_variable(string);
/*
* void var_set_variable(string name, value)
* Requires: var_clear_all_variables has been called
* Modifies: The value of description langauge variable
* named name.
* Effects: Sets the description langauge variable named name
* to have the value value.
*/
extern void var_set_variable(string, string);
/*
* void var_set_variable_to_number(string name; int number)
* Requires: var_clear_all_variables has been called
* Modifies: The value of description langauge variable
* named name.
* Effects: Sets the description langauge variable named name
* to have as its value number's ascii representation.
*/
extern void var_set_variable_to_number(string, int);
/*
* void var_set_variable_then_free_value(string name, value)
* Requires: var_clear_all_variables has been called, value is
* on the heap.
* Modifies: The value of description langauge variable
* named name, value
* Effects: Sets the description langauge variable named name
* to have the value value then frees value. This
* routine is slightly faster than calling var_set_variable
* then freeing value. It is provided mainly for
* convenience reasons.
*/
extern void var_set_variable_then_free_value(string, string);
/*
* void var_set_number_variables_to_fields(char *data, int length)
* Requires: var_clear_all_variables has been called
* Modifies: All numeric description language variables
* Effects: Treats data[0]..data[length-1] as a series of
* null-seperated fields. Sets $<number> (<number>
* here means [0-9]+ to field # <number> in data.
* Field 0 is defined to be "" as are all field #'s
* greater than the number of fields in data.
* Data[0]..data[length-1] must not be changed (or freed)
* until either this call is made again with different
* data or var_clear_all_variables is called.
*/
extern void var_set_number_variables_to_fields(char *, int);
#endif

437
zwgc/xcut.c Normal file
View File

@ -0,0 +1,437 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_xcut_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* Code to deal with handling X events: */
/* */
/****************************************************************************/
#ifndef X_DISPLAY_MISSING
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <zephyr/zephyr.h>
#include "new_memory.h"
#include "new_string.h"
#include "X_gram.h"
#include "zwgc.h"
#include "xselect.h"
#include "xmark.h"
#include "error.h"
#include "xrevstack.h"
#include "X_driver.h"
#include "xcut.h"
#ifdef CMU_ZWGCPLUS
#include "plus.h"
#include "variables.h"
#endif
/*
*
*/
extern long ttl;
static char *selected_text=NULL;
static Window selecting_in = 0;
char *
getSelectedText(void)
{
return(selected_text);
}
#ifdef notdef
static string
x_gram_to_string(x_gram *gram)
{
int i, index, len;
int last_y = -1;
string temp;
string text_so_far = string_Copy("");
char *text;
text = gram->text;
for (i=0; i<gram->numblocks; i++) {
if (last_y != -1 && last_y != gram->blocks[i].y)
text_so_far = string_Concat2(text_so_far, "\n");
index = gram->blocks[i].strindex;
len = gram->blocks[i].strlen;
temp = string_CreateFromData(text+index, len);
text_so_far = string_Concat2(text_so_far, temp);
free(temp);
last_y = gram->blocks[i].y;
}
text_so_far = string_Concat2(text_so_far, "\n");
return(text_so_far);
}
#endif
/*
*
*/
#if 0
/*ARGSUSED*/
static Bool
isShiftButton1(Display *dpy,
XEvent *event,
char *arg)
{
return(event->xbutton.state & (ShiftMask|Button1Mask));
}
/*ARGSUSED*/
static Bool
isShiftButton3(Display *dpy,
XEvent *event,
char *arg)
{
return(event->xbutton.state & (ShiftMask|Button3Mask));
}
static void
getLastEvent(Display *dpy,
unsigned int state,
XEvent *event)
{
XEvent xev;
if (state & Button1Mask) {
while(XCheckIfEvent(dpy,&xev,isShiftButton1,NULL))
*event=xev;
} else if (state & Button3Mask) {
while(XCheckIfEvent(dpy,&xev,isShiftButton3,NULL))
*event=xev;
}
}
#endif
static void
xunmark(Display *dpy,
Window w,
x_gram *gram,
XContext desc_context)
{
XPointer gramp; /* Avoid strict aliasing violation */
if (gram == NULL) {
if (XFindContext(dpy, w, desc_context, &gramp))
return;
gram = (x_gram *)gramp;
}
xmarkClear();
xmarkRedraw(dpy,w,gram,XMARK_REDRAW_OLD);
}
/* This is out here so xdestroygram can get at it */
#define PRESSOP_NONE 0 /* nothing */
#define PRESSOP_KILL 1 /* normal click */
#define PRESSOP_SEL 2 /* shift left */
#define PRESSOP_EXT 3 /* shift right */
#define PRESSOP_NUKE 4 /* ctrl */
#define PRESSOP_STOP 5 /* pressop cancelled by moving out of window */
static int current_pressop = PRESSOP_NONE;
void
xdestroygram(Display *dpy,
Window w,
XContext desc_context,
x_gram *gram)
{
struct timeval now;
int i;
gettimeofday(&now,NULL);
if ((gram->can_die.tv_sec == 0) ||
(gram->can_die.tv_sec > now.tv_sec) ||
((gram->can_die.tv_sec == now.tv_sec) &&
(gram->can_die.tv_usec > now.tv_usec)))
return;
if (w == selecting_in) {
selecting_in = 0;
xmarkClear();
}
current_pressop = PRESSOP_NONE;
XDeleteContext(dpy, w, desc_context);
XDestroyWindow(dpy, w);
delete_gram(gram);
free(gram->text);
for (i=0; i < gram->numblocks; i++)
free(gram->blocks[i].wstr);
free(gram->blocks);
#ifdef CMU_ZWGCPLUS
if (gram->notice)
list_del_notice(gram->notice);
#endif
free(gram);
#ifdef CMU_ZWGCPLUS
XFlush(dpy);
#endif
if (bottom_gram == NULL && unlinked == NULL) {
/* flush colormap here */
}
}
void
xcut(Display *dpy,
XEvent *event,
XContext desc_context)
{
XPointer gramp; /* Avoid strict aliasing violation */
x_gram *gram;
Window w = event->xany.window;
int changedbound;
/*
* If event is for a window that's not ours anymore (say we're
* in the process of deleting it...), ignore it:
*/
if (XFindContext(dpy, w, desc_context, &gramp))
return;
gram = (x_gram *)gramp;
/*
* Dispatch on the event type:
*/
switch(event->type) {
#ifdef CMU_ZWGCPLUS
case KeyPress:
{
char c;
char *plusvar;
int res, metaflag;
res = XLookupString(&(event->xkey), &c, 1, NULL, NULL);
metaflag = event->xkey.state & Mod1Mask;
/* Recheck if zwgcplus is turned on;
* Zephyr variables override zwgc variables
*/
zwgcplus = 1;
plusvar = ZGetVariable("zwgcplus")
? ZGetVariable("zwgcplus") : var_get_variable("zwgcplus");
if ((plusvar[0]=='\0') || (strcmp(plusvar,"no") == 0))
zwgcplus = 0;
else {
if (strcmp(plusvar,"no") == 0)
zwgcplus = 0;
if (strcmp(plusvar,"new") == 0)
zwgcplus = 2;
}
if (res != 0 && zwgcplus != 0)
plus_retry_notice(gram->notice, c, metaflag);
}
break;
#endif
case ClientMessage:
if ((event->xclient.message_type == XA_WM_PROTOCOLS) &&
(event->xclient.format == 32) &&
(event->xclient.data.l[0] == (long)XA_WM_DELETE_WINDOW))
xdestroygram(dpy,w,desc_context,gram);
break;
case MapNotify:
/* I don't like using the local time, but MapNotify events don't
* come with a timestamp, and there's no way to query the server
*/
if (gram->can_die.tv_sec == 0) {
gettimeofday(&(gram->can_die),NULL);
gram->can_die.tv_sec += (int) (ttl/1000);
gram->can_die.tv_usec += (ttl%1000)*1000;
}
break;
case UnmapNotify:
unlink_gram(gram);
break;
case LeaveNotify:
if (current_pressop == PRESSOP_KILL ||
current_pressop == PRESSOP_NUKE)
current_pressop = PRESSOP_STOP;
break;
case MotionNotify:
if (current_pressop == PRESSOP_SEL) {
/* getLastEvent(dpy,Button1Mask,event); */
changedbound=xmarkExtendFromFirst(gram,event->xmotion.x,
event->xmotion.y);
xmarkRedraw(dpy,w,gram,changedbound);
} else if (current_pressop == PRESSOP_EXT) {
/* getLastEvent(dpy,Button3Mask,event); */
changedbound=xmarkExtendFromNearest(gram,event->xmotion.x,
event->xmotion.y);
xmarkRedraw(dpy,w,gram,changedbound);
}
break;
case ButtonPress:
if (current_pressop != PRESSOP_NONE) {
current_pressop = PRESSOP_STOP;
} else if ((event->xbutton.button==Button4 ||
event->xbutton.button==Button5) &&
!get_bool_resource("scrollDelete","ScrollDelete",0)) {
/* Ignore scroll wheel movement. */
break;
} else if ( (event->xbutton.state)&ShiftMask ) {
if (event->xbutton.button==Button1) {
if (selecting_in)
xunmark(dpy,selecting_in,NULL,desc_context);
if (selected_text) free(selected_text);
selected_text = NULL;
if (! xselGetOwnership(dpy,w,event->xbutton.time)) {
XBell(dpy,0);
ERROR("Unable to get ownership of PRIMARY selection.\n");
selecting_in = 0;
current_pressop = PRESSOP_STOP;
} else {
selecting_in = w;
xmarkStart(gram,event->xbutton.x,event->xbutton.y);
current_pressop = PRESSOP_SEL;
}
} else if ((event->xbutton.button==Button3) &&
(w == selecting_in)) {
if (selected_text) free(selected_text);
selected_text = NULL;
changedbound=xmarkExtendFromNearest(gram,event->xbutton.x,
event->xbutton.y);
xmarkRedraw(dpy,w,gram,changedbound);
selected_text = xmarkGetText();
/* this is ok, since to get here, the selection must be owned */
current_pressop = PRESSOP_EXT;
#ifdef CMU_ZWGCPLUS
if (selected_text)
XStoreBytes(dpy, selected_text, strlen(selected_text)+1);
#endif
}
} else if ( (event->xbutton.state)&ControlMask ) {
current_pressop = PRESSOP_NUKE;
} else {
current_pressop = PRESSOP_KILL;
}
break;
case ButtonRelease:
if (current_pressop == PRESSOP_KILL) {
xdestroygram(dpy,w,desc_context,gram);
} else if (current_pressop == PRESSOP_SEL ||
current_pressop == PRESSOP_EXT) {
if (selected_text) free(selected_text);
selected_text = xmarkGetText();
#ifdef CMU_ZWGCPLUS
if (selected_text)
XStoreBytes(dpy, selected_text, strlen(selected_text)+1);
#endif
} else if (current_pressop == PRESSOP_NUKE) {
XWindowAttributes wa;
int gx,gy;
Window temp;
x_gram *next;
for (gram = bottom_gram ; gram ; gram = next) {
XGetWindowAttributes(dpy,gram->w,&wa);
XTranslateCoordinates(dpy,gram->w,wa.root,0,0,&gx,&gy,
&temp);
next = gram->above;
if ((wa.map_state == IsViewable) &&
(gx <= event->xbutton.x_root) &&
(event->xbutton.x_root < gx+wa.width) &&
(gy <= event->xbutton.y_root) &&
(event->xbutton.y_root < gy+wa.height)) {
xdestroygram(dpy,gram->w,desc_context,gram);
}
}
for (gram = unlinked ; gram ; gram = next) {
XGetWindowAttributes(dpy,gram->w,&wa);
XTranslateCoordinates(dpy,gram->w,wa.root,0,0,&gx,&gy,
&temp);
next = gram->above;
if ((wa.map_state == IsViewable) &&
(gx <= event->xbutton.x_root) &&
(event->xbutton.x_root < gx+wa.width) &&
(gy <= event->xbutton.y_root) &&
(event->xbutton.y_root < gy+wa.height)) {
xdestroygram(dpy,gram->w,desc_context,gram);
}
}
}
current_pressop = PRESSOP_NONE;
break;
case SelectionRequest:
xselProcessSelection(dpy,w,event);
break;
case SelectionClear:
xselOwnershipLost(event->xselectionclear.time);
if (w == selecting_in) {
selecting_in = 0;
xunmark(dpy,w,gram,desc_context);
if (selected_text) free(selected_text);
selected_text = NULL;
}
break;
#ifdef notdef
case ConfigureNotify:
#ifdef DEBUG
if (zwgc_debug)
printf("ConfigureNotify received for wid %lx above wid %lx\n",
(long) w,(long) event->xconfigure.above);
#endif
if (gram->above==gram) {
/* a new zgram. Straight to the bottom! */
add_to_bottom(gram);
} else if (event->xconfigure.above) {
/* some zgram was pulled to the top */
pull_to_top(gram);
} else {
/* Some zgram was pushed to the bottom */
push_to_bottom(gram);
}
/* Note that there is no option to configure a zgram to the middle */
break;
#endif
default:
break;
}
XFlush(dpy);
}
#endif

5
zwgc/xcut.h Normal file
View File

@ -0,0 +1,5 @@
/* $Id$
*
*/
void xdestroygram(Display *dpy, Window w, XContext desc_context, x_gram *gram);

55
zwgc/xerror.c Normal file
View File

@ -0,0 +1,55 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_xerror_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
#ifndef X_DISPLAY_MISSING
#include <X11/Xlib.h>
#include "mux.h"
#include "xerror.h"
int xerror_happened;
/*ARGSUSED*/
static int
xerrortrap(Display *dpy,
XErrorEvent *xerrev)
{
xerror_happened = 1;
return 0;
}
/*ARGSUSED*/
void
begin_xerror_trap(Display *dpy)
{
xerror_happened = 0;
XSetErrorHandler(xerrortrap);
}
void
end_xerror_trap(Display *dpy)
{
XSync(dpy,False);
XSetErrorHandler(NULL);
}
#endif

28
zwgc/xerror.h Normal file
View File

@ -0,0 +1,28 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#ifndef _XERROR_H_
#define _XERROR_H_
#if (!defined(lint) && !defined(SABER))
static const char rcsid_xerror_h[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
extern int xerror_happened;
void begin_xerror_trap(Display *);
void end_xerror_trap(Display *);
#endif

418
zwgc/xmark.c Normal file
View File

@ -0,0 +1,418 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#if (!defined(lint) && !defined(SABER))
static const char rcsid_xmark_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
#include <sysdep.h>
#ifndef X_DISPLAY_MISSING
#include <X11/X.h>
#include <X11/Xlib.h>
#include <zephyr/zephyr.h>
#include "X_gram.h"
#include "X_fonts.h"
#include "xmark.h"
#include "new_string.h"
int markblock[3] = { -1 , -1 , -1 };
int markchar[3] = { -1 , -1 , -1 };
int markpixel[3] = { -1 , -1 , -1 };
x_gram *markgram = NULL;
int oldblock[2] = { -1 , -1 };
int oldpixel[2] = { -1 , -1 };
x_gram *oldgram = NULL;
#define xmarkValid() \
((markgram) && \
(STARTBLOCK != -1) && (ENDBLOCK != -1) && \
(STARTCHAR != -1) && (ENDCHAR != -1) && \
(STARTPIXEL != -1) && (ENDPIXEL != -1))
void
xmarkSetBound(x_gram *gram,
int x,
int y,
int which)
{
int i, xofs, yofs;
XFontSet font;
xblock *xb;
int num_chars;
XRectangle *ink, *logical;
#ifdef MARK_DEBUG
#define RETURN \
if ((oldblock[which] != markblock[which]) || \
(oldpixel[which] != markpixel[which])) { \
printf("----- SetBound:\noldblock[%d]=%d, oldpixel[%d]=%d\nmarkblock[%d]=%d, markpixel[%d]=%d\n-----", \
which,oldblock[which],which,oldpixel[which], \
which,markblock[which],which,markpixel[which]); \
} \
return
#else
#define RETURN return
#endif
if (markgram != gram) {
xmarkClear();
markgram = gram;
} else if (which < XMARK_TEMP_BOUND) {
oldblock[which]=markblock[which];
oldpixel[which]=markpixel[which];
}
/* Start at the top, fastforward to first span not too high. */
for (i=0,xb=gram->blocks ;
(i<gram->numblocks) && (xb->y2 < y) ;
i++,xb++) ;
/* the point is after the end */
if (i==gram->numblocks) {
markblock[which]=i;
markchar[which]=0;
markpixel[which]=0;
RETURN;
}
/* is the point before the beginning of the line? */
if (x <= xb->x1) {
markblock[which]=i;
markchar[which]=0;
markpixel[which]=0;
RETURN;
}
/* is the point in the nether space between this line and the last? */
if (y < xb->y1) {
markblock[which]=i;
markchar[which]=0;
markpixel[which]=0;
RETURN;
}
for (yofs=xb->y1;(i<gram->numblocks) && (xb->y1 == yofs);i++,xb++) {
if (x <= xb->x2) {
markblock[which]=i;
xofs=xb->x1;
if ((x < xofs) || (y < xb->y1)) {
markchar[which]=0;
RETURN;
}
font = xb->font;
#ifdef X_HAVE_UTF8_STRING
Xutf8TextPerCharExtents(font, xb->wstr, xb->wlen,
NULL, NULL, -1, &num_chars, NULL, NULL);
#else
XwcTextPerCharExtents(font, (wchar_t *)xb->wstr, xb->wlen,
NULL, NULL, -1, &num_chars, NULL, NULL);
#endif
ink = malloc(num_chars * sizeof(XRectangle));
logical = malloc(num_chars * sizeof(XRectangle));
#ifdef X_HAVE_UTF8_STRING
Xutf8TextPerCharExtents(font, xb->wstr, xb->wlen,
ink, logical, num_chars, &num_chars, NULL, NULL);
#else
XwcTextPerCharExtents(font, (wchar_t *)xb->wstr, xb->wlen,
ink, logical, num_chars, &num_chars, NULL, NULL);
#endif
for (i=0;i<num_chars;i++) {
if (x <= xofs + logical[i].x + logical[i].width) {
markchar[which]=i;
markpixel[which]=xofs + logical[i].x - xb->x1;
free(ink);
free(logical);
RETURN;
}
}
free(ink);
free(logical);
}
}
/* The endpoint is after the end of the block if the loop ends */
markblock[which]=i;
markchar[which]=0;
markpixel[which]=0;
RETURN;
}
/* needs both bounds to be valid (!= -1) */
static int
xmarkNearest(int x,
int y)
{
int middle;
xmarkSetBound(markgram,x,y,XMARK_TEMP_BOUND);
middle=(ENDBLOCK+STARTBLOCK)/2;
if (markblock[XMARK_TEMP_BOUND] < middle)
return(XMARK_START_BOUND);
else if (markblock[XMARK_TEMP_BOUND] > middle)
return(XMARK_END_BOUND);
else {
middle=(ENDCHAR+STARTCHAR)/2;
if (markchar[XMARK_TEMP_BOUND] < middle)
return(XMARK_START_BOUND);
else
return(XMARK_END_BOUND);
}
}
static void
xmarkExpose(Display *dpy,
Window w,
x_gram *gram,
unsigned int b1,
unsigned int p1,
unsigned int b2,
unsigned int p2)
{
#define swap(x,y) temp=(x); (x)=(y); (y)=temp
unsigned int i,temp;
XEvent event;
#define expose (event.xexpose)
if (((int)b1==-1) || ((int)p1==-1) || ((int)b2==-1) || ((int)p2==-1))
return;
if ((b1 > b2) || ((b1 == b2) && (p1 > p2))) {
swap(b1,b2);
swap(p1,p2);
}
#if defined(_IBMR2) && !defined(__GNUC__) && defined(RS6000_OPT_BUG)
/* A version of the AIX 3.1 RS/6000 C compiler needs this to prevent
a core dump in the loop below. */
&b1;
#endif
expose.type=Expose;
expose.display=dpy;
expose.window=w;
for (i=b1;i<=b2;i++) {
if (b1==b2) {
expose.x=gram->blocks[i].x1+p1;
expose.y=gram->blocks[i].y1;
expose.width=p2-p1;
expose.height=gram->blocks[i].y2-gram->blocks[i].y1;
expose.count=0;
} else if (i==b1) {
expose.x=gram->blocks[i].x1+p1;
expose.y=gram->blocks[i].y1;
expose.width=gram->blocks[i].x2-p1;
expose.height=gram->blocks[i].y2-gram->blocks[i].y1;
expose.count=b2-i;
} else if (i==b2) {
expose.x=gram->blocks[i].x1;
expose.y=gram->blocks[i].y1;
expose.width=p2;
expose.height=gram->blocks[i].y2-gram->blocks[i].y1;
expose.count=b2-i;
} else {
expose.x=gram->blocks[i].x1;
expose.y=gram->blocks[i].y1;
expose.width=gram->blocks[i].x2-gram->blocks[i].x1;
expose.height=gram->blocks[i].y2-gram->blocks[i].y1;
expose.count=b2-i;
}
#ifdef MARK_DEBUG
if (expose.width && expose.height) {
printf("---- markExpose:\nb1=%d p1=%d b2=%d p2=%d\n",b1,p1,b2,p2);
printf("x=%d y=%d w=%d h=%d\n-----",
expose.x,expose.y,expose.width,expose.height);
}
#endif
if ((expose.width && expose.height) || (expose.count == 0))
XSendEvent(dpy,w,True,ExposureMask,&event);
}
}
/* Public functions: */
void
xmarkRedraw(Display *dpy,
Window w,
x_gram *gram,
int range)
{
#define ob1 ((unsigned int) oldblock[XMARK_START_BOUND])
#define ob2 ((unsigned int) oldblock[XMARK_END_BOUND])
#define nb1 ((unsigned int) markblock[XMARK_START_BOUND])
#define nb2 ((unsigned int) markblock[XMARK_END_BOUND])
#define op1 ((unsigned int) oldpixel[XMARK_START_BOUND])
#define op2 ((unsigned int) oldpixel[XMARK_END_BOUND])
#define np1 ((unsigned int) markpixel[XMARK_START_BOUND])
#define np2 ((unsigned int) markpixel[XMARK_END_BOUND])
if (range==XMARK_REDRAW_CURRENT) {
if (!markgram) return;
xmarkExpose(dpy,w,gram,nb1,np1,nb2,np2);
} else if (range==XMARK_REDRAW_OLD) {
if (!oldgram) return;
xmarkExpose(dpy,w,gram,ob1,op1,ob2,op2);
} else if (range==XMARK_REDRAW_START) {
if (!markgram) return;
xmarkExpose(dpy,w,gram,ob1,op1,nb1,np1);
} else if (range==XMARK_REDRAW_END) {
if (!markgram) return;
xmarkExpose(dpy,w,gram,ob2,op2,nb2,np2);
}
#ifdef DEBUG
else {
printf("xmarkRedraw: This shouldn't happen!\n");
}
#endif
}
/* needs both bounds to be valid (!= -1) */
int
xmarkSecond(void)
{
if (STARTBLOCK > ENDBLOCK)
return(XMARK_START_BOUND);
else if (STARTBLOCK < ENDBLOCK)
return(XMARK_END_BOUND);
else {
if (STARTCHAR > ENDCHAR)
return(XMARK_START_BOUND);
else if (STARTCHAR < ENDCHAR)
return(XMARK_END_BOUND);
else
return(XMARK_END_BOUND);
}
}
void
xmarkClear(void)
{
oldblock[0]=markblock[0];
oldblock[1]=markblock[1];
oldpixel[0]=markpixel[0];
oldpixel[1]=markpixel[1];
oldgram=markgram;
markblock[0] = -1;
markblock[1] = -1;
markchar[0] = -1;
markchar[1] = -1;
markpixel[0] = -1;
markpixel[1] = -1;
markgram=NULL;
}
int
xmarkExtendFromFirst(x_gram *gram,
int x,
int y)
{
if (markgram != gram) {
xmarkClear();
markgram = gram;
}
if (STARTBLOCK == -1) {
xmarkStart(gram,x,y);
xmarkEnd(gram,x,y);
return(XMARK_REDRAW_CURRENT);
} else if (ENDBLOCK == -1) {
xmarkEnd(gram,x,y);
return(XMARK_REDRAW_CURRENT);
} else {
xmarkSetBound(gram,x,y,XMARK_END_BOUND);
return(XMARK_REDRAW_END);
}
}
int
xmarkExtendFromNearest(x_gram *gram,
int x,
int y)
{
int bound;
if (markgram != gram) {
xmarkClear();
markgram = gram;
}
if (STARTBLOCK == -1) {
xmarkStart(gram,x,y);
xmarkEnd(gram,x,y);
return(XMARK_REDRAW_CURRENT);
} else if (ENDBLOCK == -1) {
xmarkEnd(gram,x,y);
return(XMARK_REDRAW_CURRENT);
} else {
xmarkSetBound(gram,x,y,bound=xmarkNearest(x,y));
return(bound==XMARK_START_BOUND?XMARK_REDRAW_START:XMARK_REDRAW_END);
}
}
char *
xmarkGetText(void)
{
int i, idx, len;
int last_y = -1;
string temp;
string text_so_far = string_Copy("");
char *text = markgram->text;
int startblock,endblock,startchar,endchar;
if (xmarkValid()) {
if (xmarkSecond() == XMARK_END_BOUND) {
startblock=STARTBLOCK;
endblock=ENDBLOCK;
startchar=STARTCHAR;
endchar=ENDCHAR;
} else {
startblock=ENDBLOCK;
endblock=STARTBLOCK;
startchar=ENDCHAR;
endchar=STARTCHAR;
}
for (i=startblock; i<=endblock; i++) {
if (last_y != -1 && last_y != markgram->blocks[i].y)
text_so_far = string_Concat2(text_so_far, "\n");
idx = markgram->blocks[i].strindex;
len = markgram->blocks[i].strlen;
if (startblock == endblock)
temp = string_CreateFromData(text+idx+startchar,
endchar-startchar);
else if (i==startblock)
temp = string_CreateFromData(text+idx+startchar,len-startchar);
else if (i==endblock)
temp = string_CreateFromData(text+idx,endchar);
else
temp = string_CreateFromData(text+idx,len);
text_so_far = string_Concat2(text_so_far, temp);
free(temp);
last_y = markgram->blocks[i].y;
}
}
return(text_so_far);
}
#endif /* X_DISPLAY_MISSING */

52
zwgc/xmark.h Normal file
View File

@ -0,0 +1,52 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef _XMARK_H_
#define _XMARK_H_
#define XMARK_START_BOUND 0
#define XMARK_END_BOUND 1
#define XMARK_TEMP_BOUND 2
#define XMARK_REDRAW_CURRENT 1
#define XMARK_REDRAW_OLD 2
#define XMARK_REDRAW_START 3
#define XMARK_REDRAW_END 4
#define xmarkStart(gram,x,y) xmarkSetBound(gram,x,y,XMARK_START_BOUND)
#define xmarkEnd(gram,x,y) xmarkSetBound(gram,x,y,XMARK_END_BOUND)
extern int markblock[];
extern int markchar[];
extern int markpixel[];
extern x_gram *markgram;
#define STARTBLOCK (markblock[XMARK_START_BOUND])
#define ENDBLOCK (markblock[XMARK_END_BOUND])
#define STARTCHAR (markchar[XMARK_START_BOUND])
#define ENDCHAR (markchar[XMARK_END_BOUND])
#define STARTPIXEL (markpixel[XMARK_START_BOUND])
#define ENDPIXEL (markpixel[XMARK_END_BOUND])
extern void xmarkSetBound(x_gram *, int, int, int);
extern int xmarkSecond(void);
extern void xmarkRedraw(Display *, Window, x_gram *, int);
extern void xmarkClear(void);
extern int xmarkExtendFromFirst(x_gram *, int, int);
extern int xmarkExtendFromNearest(x_gram *, int, int);
extern char *xmarkGetText(void);
#endif

271
zwgc/xrevstack.c Normal file
View File

@ -0,0 +1,271 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_xrevstack_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
#ifndef X_DISPLAY_MISSING
#ifndef TRUEREVSTACK
#include <zephyr/zephyr.h>
#include "X_gram.h"
#include "xrevstack.h"
x_gram *bottom_gram = NULL;
x_gram *unlinked = NULL;
int reverse_stack = 0;
void
add_to_bottom(x_gram *gram)
{
if (bottom_gram) {
bottom_gram->below = gram;
gram->below = NULL;
gram->above = bottom_gram;
bottom_gram = gram;
} else {
gram->above = NULL;
gram->below = NULL;
bottom_gram = gram;
}
}
/*ARGSUSED*/
void
pull_to_top(x_gram *gram)
{
}
/*ARGSUSED*/
void
push_to_bottom(x_gram *gram)
{
}
void
delete_gram(x_gram *gram)
{
if (gram == bottom_gram) {
if (gram->above) {
bottom_gram = gram->above;
bottom_gram->below = NULL;
} else {
bottom_gram = NULL;
}
} else if (gram == unlinked) {
if (gram->above) {
unlinked = gram->above;
unlinked->below = NULL;
} else {
unlinked = NULL;
}
} else {
if (gram->above)
gram->above->below = gram->below;
gram->below->above = gram->above;
}
/* fix up above & below pointers so that calling delete_gram
again is safe */
gram->below = gram;
gram->above = gram;
}
void
unlink_gram(x_gram *gram)
{
delete_gram(gram);
if (unlinked) {
unlinked->below = gram;
gram->below = NULL;
gram->above = unlinked;
unlinked = gram;
} else {
gram->above = NULL;
gram->below = NULL;
unlinked = gram;
}
}
#endif
#ifdef TRUEREVSTACK
#include "X_gram.h"
#include "zwgc.h"
#include <stdio.h>
x_gram *bottom_gram=NULL;
static x_gram *top_gram=NULL;
#ifdef DEBUG
void
print_gram_list(char *str)
{
x_gram *gram;
char buf[80];
if (zwgc_debug) {
printf("----- From function %s: Top of tree\n",str);
if (top_gram)
if (top_gram->above)
printf("Tree munged: something above top_gram\n");
for (gram=top_gram;gram;gram=gram->below) {
strncpy(buf,gram->text,63);
buf[63]='\0';
printf("wid %lx txt: %s\n",(long) gram->w,buf);
}
if (bottom_gram)
if (bottom_gram->below)
printf("Tree munged: something below bottom_gram\n");
printf("----- Bottom of tree\n");
}
}
#endif
void
pull_to_top(x_gram *gram)
{
if (gram==top_gram) {
/* already here */
return;
} else if (top_gram==NULL) {
/* no grams at all. Make gram both top and bottom */
top_gram=gram;
bottom_gram=gram;
} else if (gram==bottom_gram) {
/* bottom gram is special case */
bottom_gram=bottom_gram->above;
bottom_gram->below=NULL;
top_gram->above=gram;
gram->below=top_gram;
top_gram=gram;
} else {
/* normal case of a gram in the middle */
gram->above->below=gram->below;
gram->below->above=gram->above;
top_gram->above=gram;
gram->below=top_gram;
gram->above=NULL;
top_gram=gram;
}
#ifdef DEBUG
print_gram_list("pull_to_top");
#endif
}
void
push_to_bottom(x_gram *gram)
{
if (gram==bottom_gram) {
/* already here */
return;
} else if (bottom_gram==NULL) {
/* no grams at all. Make gram both top and bottom */
gram->above=NULL;
gram->below=NULL;
top_gram=gram;
bottom_gram=gram;
} else if (gram==top_gram) {
/* top gram is special case */
top_gram=top_gram->below;
top_gram->above=NULL;
bottom_gram->below=gram;
gram->above=bottom_gram;
bottom_gram=gram;
} else {
/* normal case of a gram in the middle */
gram->above->below=gram->below;
gram->below->above=gram->above;
bottom_gram->below=gram;
gram->above=bottom_gram;
gram->below=NULL;
bottom_gram=gram;
}
#ifdef DEBUG
print_gram_list("push_to_bottom");
#endif
}
void
unlink_gram(x_gram *gram)
{
if (top_gram==bottom_gram) {
/* the only gram in the stack */
top_gram=NULL;
bottom_gram=NULL;
} else if (gram==top_gram) {
top_gram=gram->below;
top_gram->above=NULL;
} else if (gram==bottom_gram) {
bottom_gram=gram->above;
bottom_gram->below=NULL;
} else {
gram->above->below=gram->below;
gram->below->above=gram->above;
}
#ifdef DEBUG
print_gram_list("unlink_gram");
#endif
}
#ifdef notdef
void
add_to_top(x_gram *gram)
{
if (top_gram==NULL) {
gram->above=NULL;
gram->below=NULL;
top_gram=gram;
bottom_gram=gram;
} else {
top_gram->above=gram;
gram->above=NULL;
gram->below=top_gram;
top_gram=gram;
}
#ifdef DEBUG
print_gram_list("add_to_top");
#endif
}
#endif
void
add_to_bottom(x_gram *gram)
{
if (bottom_gram==NULL) {
gram->above=NULL;
gram->below=NULL;
top_gram=gram;
bottom_gram=gram;
} else {
bottom_gram->below=gram;
gram->above=bottom_gram;
gram->below=NULL;
bottom_gram=gram;
}
#ifdef DEBUG
print_gram_list("add_to_bottom");
#endif
}
#endif /* TRUEREVSTACK */
#endif /* X_DISPLAY_MISSING */

33
zwgc/xrevstack.h Normal file
View File

@ -0,0 +1,33 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#ifndef _XREVSTACK_H_
#define _XREVSTACK_H_
#if (!defined(lint) && !defined(SABER))
static const char rcsid_xrevstack_h[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
extern x_gram *bottom_gram; /* for testing against NULL */
extern x_gram *unlinked;
extern int reverse_stack; /* is reverse stack on? */
extern void add_to_bottom(x_gram *);
extern void delete_gram(x_gram *);
extern void unlink_gram(x_gram *);
extern void pull_to_top(x_gram *);
extern void push_to_bottom(x_gram *);
#endif /* _XREVSTACK_H_ */

214
zwgc/xselect.c Normal file
View File

@ -0,0 +1,214 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_xselect_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/* xselect.c - ICCCM compliant cut-and-paste */
/* also includes some other ICCCMisms, such as the WM_PROTOCOL handling */
#ifndef X_DISPLAY_MISSING
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xatom.h>
#include "new_string.h"
#include "xselect.h"
extern char *getSelectedText(void);
static Time ownership_start = CurrentTime;
static Time ownership_end = CurrentTime;
Atom XA_WM_PROTOCOLS,XA_WM_DELETE_WINDOW;
static Atom ZA_TARGETS,ZA_MULTIPLE,ZA_TIMESTAMP,ZA_ATOM_PAIR;
static struct _ZAtom {
Atom *patom;
char *name;
} ZAtom[] = {
{&XA_WM_PROTOCOLS,"WM_PROTOCOLS"},
{&XA_WM_DELETE_WINDOW,"WM_DELETE_WINDOW"},
{&ZA_TARGETS,"TARGETS"},
{&ZA_MULTIPLE,"MULTIPLE"},
{&ZA_TIMESTAMP,"TIMESTAMP"},
{&ZA_ATOM_PAIR,"ATOM_PAIR"}
};
#define NumZAtoms (sizeof(ZAtom)/sizeof(struct _ZAtom))
/* internal static functions */
static void
xselNotify(Display *dpy,
XSelectionRequestEvent *selreq,
Atom property)
{
XSelectionEvent ev;
ev.type=SelectionNotify;
ev.requestor=selreq->requestor;
ev.selection=selreq->selection;
ev.target=selreq->target;
ev.property=property;
ev.time=selreq->time;
XSendEvent(dpy,ev.requestor,False,0,(XEvent *) &ev);
}
/* pRequestAtoms and RequestAtoms should have the same size. */
static Atom *pRequestAtoms[] = {
&ZA_TARGETS,&ZA_MULTIPLE,&ZA_TIMESTAMP,NULL
};
static Atom RequestAtoms[] = {
None,None,None,XA_STRING
};
#define NumRequestAtoms (sizeof(RequestAtoms)/sizeof(Atom))
#define PROP(prop,targ) ((prop)!=None?(prop):(targ))
#define ChangeProp(type,format,data,size) \
XChangeProperty(dpy,w,PROP(property,target),(type),(format), \
PropModeReplace, (unsigned char *) (data),(size))
static void
xselSetProperties(Display *dpy,
Window w,
Atom property,
Atom target,
XSelectionRequestEvent *selreq)
{
if (target==ZA_TARGETS) {
ChangeProp(XA_ATOM,32,RequestAtoms,NumRequestAtoms);
XSync(dpy,0);
} else if (target==ZA_MULTIPLE) {
Atom atype;
int aformat;
unsigned char *alistp; /* Avoid strict aliasing violation, we hope */
Atom *alist;
unsigned long alistsize,i;
XGetWindowProperty(dpy,w,property,0L,0L,False,ZA_ATOM_PAIR,&atype,
&aformat,&i,&alistsize,&alistp);
if (alistsize)
XGetWindowProperty(dpy,w,property,0L,alistsize/sizeof(Atom),False,
ZA_ATOM_PAIR,&atype,&aformat,&alistsize,&i, &alistp);
alist = (Atom *)alistp;
alistsize/=(sizeof(Atom)/4);
for (i=0;i<alistsize;i+=2)
xselSetProperties(dpy,w,alist[i+1],alist[i],selreq);
XFree((char *) alist);
} else if (target==ZA_TIMESTAMP) {
ChangeProp(XA_INTEGER,32,&ownership_start,1);
XSync(dpy,0);
} else if (target==XA_STRING) {
char *selected;
selected = getSelectedText();
if (selected) {
ChangeProp(XA_STRING,8,selected,string_Length(selected));
} else {
/* This should only happen if the pasting client is out of
spec (or if this program is buggy), but it could happen */
#ifdef DEBUG
fprintf(stderr,
"SelectionRequest event received for unowned selection: requestor wid=0x%lx", (unsigned long)w);
#endif
ChangeProp(XA_STRING,8,"",0);
}
XSync(dpy,0);
}
xselNotify(dpy,selreq,property);
}
/* global functions */
void
xicccmInitAtoms(Display *dpy)
{
unsigned int i;
for (i=0;i<NumZAtoms;i++)
*(ZAtom[i].patom)=XInternAtom(dpy,ZAtom[i].name,False);
for (i=0;i<NumRequestAtoms;i++)
if (pRequestAtoms[i])
RequestAtoms[i] = *(pRequestAtoms[i]);
}
int
xselGetOwnership(Display *dpy,
Window w,
Time when)
{
int temp;
XSetSelectionOwner(dpy,XA_PRIMARY,w,when);
temp=(w == XGetSelectionOwner(dpy,XA_PRIMARY));
if (temp)
ownership_start = when;
return(temp);
}
/* Get the selection. Return !0 if success, 0 if fail */
int
xselProcessSelection(Display *dpy,
Window w,
XEvent *event)
{
XSelectionRequestEvent *selreq = &(event->xselectionrequest);
#ifdef DEBUG
if ((selreq->owner != w) || (selreq->selection != XA_PRIMARY))
fprintf(stderr,"SelectionRequest event has bogus field values\n");
#endif
if ((ownership_start == CurrentTime) ||
(((selreq->time != CurrentTime) &&
(selreq->time < ownership_start)) ||
((ownership_end != CurrentTime) &&
(ownership_end > ownership_start) &&
(selreq->time > ownership_end))))
xselNotify(dpy,selreq,None);
else
xselSetProperties(dpy,selreq->requestor,selreq->property,selreq->target,
selreq);
return(1);
}
void
xselOwnershipLost(Time when)
{
ownership_end = when;
}
/*ARGSUSED*/
void
xselGiveUpOwnership(Display *dpy,
Window w)
{
XSetSelectionOwner(dpy,XA_PRIMARY,None,ownership_start);
ownership_end=ownership_start; /* Is this right? what should I use? */
}
#endif /* X_DISPLAY_MISSING */

28
zwgc/xselect.h Normal file
View File

@ -0,0 +1,28 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef _XSELECT_H_
#define _XSELECT_H_
extern void xicccmInitAtoms(Display *);
extern int xselGetOwnership(Display *, Window, Time);
extern int xselProcessSelection(Display *, Window, XEvent *);
extern void xselOwnershipLost(Time);
extern void xselGiveUpOwnership(Display *, Window);
extern Atom XA_WM_PROTOCOLS, XA_WM_DELETE_WINDOW;
#endif

833
zwgc/xshow.c Normal file
View File

@ -0,0 +1,833 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_xshow_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
#ifndef X_DISPLAY_MISSING
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <zephyr/zephyr.h>
#include "pointer_dictionary.h"
#include "new_memory.h"
#include "new_string.h"
#include "formatter.h"
#include "variables.h"
#include "zwgc.h"
#include "X_driver.h"
#include "X_fonts.h"
#include "X_gram.h"
#include "xmode_stack.h"
#ifdef CMU_ZWGCPLUS
#include <zephyr/zephyr.h>
#include "xrevstack.h"
#include "plus.h"
#include "xcut.h"
#endif
#define max(a,b) ((a)>(b)?(a):(b))
XContext desc_context;
extern int internal_border_width;
extern unsigned long default_bgcolor;
extern unsigned long default_fgcolor;
void
xshowinit(void)
{
desc_context = XUniqueContext();
}
struct res_dict_type {
pointer_dictionary dict;
char * resname_suffix;
char * resclass;
};
static char *
xres_get_resource(struct res_dict_type *restype,
char *style)
{
char *desc;
pointer_dictionary_binding *binding;
int exists;
char *value;
desc=string_Concat("style.", style);
desc=string_Concat2(desc, restype->resname_suffix);
if (!restype->dict)
restype->dict = pointer_dictionary_Create(37);
binding = pointer_dictionary_Define(restype->dict, desc, &exists);
if (exists) {
free(desc);
return((string) binding->value);
} else {
value=get_string_resource(desc, restype->resclass);
free(desc);
if (value==NULL)
pointer_dictionary_Delete(restype->dict, binding);
else
binding->value=(pointer) value;
return value; /* If resource returns NULL, return NULL also */
}
}
static struct res_dict_type geometry_resources = {
NULL, ".geometry", "StyleKey.Style1.Style2.Style3.GeometryKey",
};
static struct res_dict_type bgcolor_resources = {
NULL, ".background", "StyleKey.Style1.Style2.Style3.BackgroundKey",
};
#define xres_get_geometry(style) xres_get_resource(&geometry_resources,style)
#define xres_get_bgcolor(style) xres_get_resource(&bgcolor_resources,style)
static struct res_dict_type fgcolor_resources = {
NULL, ".foreground",
"StyleKey.Style1.Style2.Style3.SubstyleKey.Substyle.ForegroundKey",
};
/*ARGSUSED*/
static char *
mode_to_colorname (Display *dpy,
char *style,
xmode *mode)
{
char *desc, *result;
desc = string_Concat (style, ".substyle.");
desc = string_Concat2 (desc, mode->substyle);
result = xres_get_resource (&fgcolor_resources, desc);
free (desc);
return result;
}
static void
fixup_and_draw(Display *dpy,
char *style,
xauxblock *auxblocks,
xblock *blocks,
int num,
xlinedesc *lines,
int numlines,
int beepcount)
{
int gram_xalign = 1;
int gram_yalign = 1;
int gram_xpos, gram_ypos, gram_xsize, gram_ysize;
x_gram *gram;
int strindex = 0;
int line, block=0;
int maxwidth=0, chars=0, maxascent, maxdescent;
int ssize, lsize,csize, rsize, width = 0;
int i, ascent, descent;
int yofs = internal_border_width;
int lofs, cofs, rofs;
int ystart,yend;
char *bgstr, *geometry, xpos[10], ypos[10], xfrom, yfrom;
XFontSetExtents *fse;
gram = (x_gram *)malloc(sizeof(x_gram));
/* Find total lengths of left, center, and right parts. Also find the
length of the longest line and the total number of characters. */
for (line = 0; line < numlines; line++) {
lsize = csize = rsize = 0;
maxascent = maxdescent = 0;
/* add up sizes for each block, get max ascent and descent */
for (i = 0; i < lines[line].numblock; i++, block++) {
chars += auxblocks[block].len;
#ifdef X_HAVE_UTF8_STRING
ssize = Xutf8TextEscapement(auxblocks[block].font,
blocks[block].wstr,
blocks[block].wlen);
#else
ssize = XwcTextEscapement(auxblocks[block].font,
(wchar_t *)blocks[block].wstr,
blocks[block].wlen);
#endif
auxblocks[block].width = ssize;
fse = XExtentsOfFontSet(auxblocks[block].font);
ascent = -fse->max_logical_extent.y;
descent = fse->max_logical_extent.y + fse->max_logical_extent.height;
if (ascent > maxascent)
maxascent = ascent;
if (descent > maxdescent)
maxdescent = descent;
switch (auxblocks[block].align) {
case LEFTALIGN:
lsize += ssize;
break;
case CENTERALIGN:
csize += ssize;
break;
case RIGHTALIGN:
rsize += ssize;
break;
}
}
/* save what we need to do size fixups */
if (maxascent > lines[line].ascent)
lines[line].ascent = maxascent;
if (maxdescent > lines[line].descent)
lines[line].descent = maxdescent;
lines[line].lsize = lsize;
lines[line].csize = csize;
lines[line].rsize = rsize;
/* get width of line and see if it is bigger than the max width */
switch ((lsize ? 1 : 0) + (csize ?2 : 0) + (rsize ? 4 : 0)) {
#ifdef DEBUG
default:
abort();
#endif
case 0:
width = 0;
break;
case 1:
width = lsize;
break;
case 2:
width = csize;
break;
case 3:
/* in all these cases, we just want to add the width of *any*
space, so the first font will do just fine. */
/* XXX implicit assumption that a line must have at least one
block, so that there is indeed a reasonable font in
auxblocks[0].font */
width = lsize * 2 + csize + XmbTextEscapement(auxblocks[0].font, " ", 1);
break;
case 4:
width = rsize;
break;
case 5:
width = lsize + rsize + XmbTextEscapement(auxblocks[0].font, " ", 1);
break;
case 6:
width = csize + rsize * 2 + XmbTextEscapement(auxblocks[0].font, " ", 1);
break;
case 7:
width = max(lsize, rsize) * 2 + csize +
XmbTextEscapement(auxblocks[0].font, " ", 1) * 2;
break;
}
if (width > maxwidth)
maxwidth = width;
}
/* fixup x,y for each block, create big string and indices into it */
/* set x1,y1,x2,y2 of each block also. */
gram->text = (char *)malloc(chars);
block = 0;
for (line = 0; line < numlines; line++) {
lofs = internal_border_width;
cofs = ((maxwidth - lines[line].csize) >> 1) + internal_border_width;
rofs = maxwidth - lines[line].rsize + internal_border_width;
ystart = yofs;
yofs += lines[line].ascent;
yend = yofs + lines[line].descent + 1; /* +1 because lines look scrunched
without it. */
for (i = 0; i < lines[line].numblock; i++, block++) {
blocks[block].font = auxblocks[block].font;
switch (auxblocks[block].align) {
case LEFTALIGN:
blocks[block].x = lofs;
blocks[block].x1 = lofs;
lofs += auxblocks[block].width;
blocks[block].x2 = lofs;
break;
case CENTERALIGN:
blocks[block].x = cofs;
blocks[block].x1 = cofs;
cofs += auxblocks[block].width;
blocks[block].x2 = cofs;
break;
case RIGHTALIGN:
blocks[block].x = rofs;
blocks[block].x1 = rofs;
rofs += auxblocks[block].width;
blocks[block].x2 = rofs;
break;
}
blocks[block].y = yofs;
blocks[block].y1 = ystart;
blocks[block].y2 = yend;
blocks[block].strindex = strindex;
blocks[block].strlen = auxblocks[block].len;
strncpy(gram->text + strindex, auxblocks[block].str,
auxblocks[block].len);
strindex += blocks[block].strlen;
}
yofs = yend;
}
geometry = var_get_variable("X_geometry");
if (geometry[0] == '\0')
geometry = xres_get_geometry(style);
if (geometry == NULL)
geometry = var_get_variable("default_X_geometry");
if (geometry[0] == '\0')
geometry = "+0+0";
sscanf(geometry, "%c%[0123456789c]%c%[0123456789c]", &xfrom, xpos,
&yfrom, ypos);
if (xpos[0] == 'c') {
gram_xalign = 0;
gram_xpos = 0;
} else
gram_xpos = atoi(xpos);
if (xfrom == '-')
gram_xalign *= -1;
if (ypos[0] == 'c') {
gram_yalign = 0;
gram_ypos = 0;
} else
gram_ypos = atoi(ypos);
if (yfrom == '-')
gram_yalign *= -1;
bgstr = var_get_variable("X_background");
if (bgstr[0] == '\0')
bgstr = xres_get_bgcolor(style);
if (bgstr == NULL)
bgstr = var_get_variable("default_X_background");
if (bgstr[0]=='\0')
gram->bgcolor = default_bgcolor;
if (bgstr && bgstr[0])
gram->bgcolor = x_string_to_color(bgstr, default_bgcolor);
gram_xsize = maxwidth + (internal_border_width << 1);
gram_ysize = yofs + internal_border_width;
gram->numblocks = num;
gram->blocks = blocks;
#ifdef CMU_ZWGCPLUS
gram->notice = get_stored_notice();
#endif
x_gram_create(dpy, gram, gram_xalign, gram_yalign, gram_xpos,
gram_ypos, gram_xsize, gram_ysize, beepcount);
}
/* Silly almost-but-not-quite-useless helper function */
static char *
no_dots_downcase_var(char *str)
{
register char *var, *var2;
var = string_Downcase(var_get_variable(str));
var2 = var;
while (*var++)
if (*var == '.')
*var = '_';
return(var2);
}
inline static XFontSet
mode_to_font(Display *dpy, char *style, xmode *mode) {
return get_font(dpy,
style,
mode->font ? mode->font : mode->substyle,
mode->size,
mode->bold + mode->italic * 2);
}
inline static int
envmatch(desctype *desc, char *str) {
int len = strlen(str);
return desc->len == len && strncasecmp(desc->str, str, len) == 0;
}
void
xshow(Display *dpy, desctype *desc, int numstr, int numnl)
{
XFontSet font;
XFontSetExtents *fse;
xmode_stack modes = xmode_stack_create();
xmode curmode;
xlinedesc *lines;
xblock *blocks;
xauxblock *auxblocks;
int nextblock=0;
int line=0,linestart=0;
char *style;
int free_style = 0;
int beepcount = 0;
char *notice_charset = var_get_variable("notice_charset");
int i;
lines = (xlinedesc *)malloc(sizeof(xlinedesc) * (numnl + 1));
blocks = (xblock *)malloc(sizeof(xblock) * numstr);
auxblocks = (xauxblock *)malloc(sizeof(xauxblock) * numstr);
memset(&curmode, 0, sizeof(curmode));
curmode.bold = 0;
curmode.italic = 0;
curmode.size = MEDIUM_SIZE;
curmode.align = LEFTALIGN;
curmode.expcolor = 0;
curmode.substyle = string_Copy("default");
curmode.font = NULL;
style = var_get_variable("style");
if (style[0] == '\0') {
style = string_Concat(no_dots_downcase_var("class"), ".");
style = string_Concat2(style, no_dots_downcase_var("instance"));
style = string_Concat2(style, ".");
style = string_Concat2(style, no_dots_downcase_var("sender"));
string_Downcase(style);
free_style = 1;
}
for (; desc->code != DT_EOF; desc = desc->next) {
switch (desc->code) {
case DT_ENV:
xmode_stack_push(modes, curmode);
curmode.substyle = string_Copy(curmode.substyle);
if (curmode.font)
curmode.font = string_Copy(curmode.font);
if (envmatch(desc, "roman")) {
curmode.bold = 0;
curmode.italic = 0;
} else if (envmatch(desc, "bold") || envmatch(desc, "b"))
curmode.bold = 1;
else if (envmatch(desc, "italic") || envmatch(desc, "i"))
curmode.italic = 1;
else if (envmatch(desc, "large"))
curmode.size = LARGE_SIZE;
else if (envmatch(desc, "medium"))
curmode.size = MEDIUM_SIZE;
else if (envmatch(desc, "small"))
curmode.size = SMALL_SIZE;
else if (envmatch(desc, "left") || envmatch(desc, "l"))
curmode.align = LEFTALIGN;
else if (envmatch(desc, "center") || envmatch(desc, "c"))
curmode.align = CENTERALIGN;
else if (envmatch(desc, "right") || envmatch(desc, "r"))
curmode.align = RIGHTALIGN;
else if (envmatch(desc, "beep"))
beepcount++;
else if (envmatch(desc, "font")) {
/* lookahead needed. desc->next->str should be the
font name, and desc->next->next->code should be
a DT_END*/
if ((desc->next) &&
(desc->next->next) &&
(desc->next->code == DT_STR) &&
(desc->next->next->code == DT_END)) {
/* Since @font mutates the current environment, we have
to pop the environment that this case usually pushes */
free(curmode.substyle);
curmode = xmode_stack_top(modes);
xmode_stack_pop(modes);
/* mutating... */
curmode.size = SPECIAL_SIZE; /* This is an @font() */
curmode.font = string_CreateFromData(desc->next->str,
desc->next->len);
/* skip over the rest of the @font */
desc = desc->next->next;
}
} else if (envmatch(desc, "color")) {
/* lookahead needed. desc->next->str should be the
font name, and desc->next->next->code should be
a DT_END*/
if ((desc->next) &&
(desc->next->next) &&
(desc->next->code == DT_STR) &&
(desc->next->next->code == DT_END)) {
char *colorname;
/* Since @font mutates the current environment, we have
to pop the environment that this case usually pushes */
free(curmode.substyle);
curmode = xmode_stack_top(modes);
xmode_stack_pop(modes);
/* mutating... */
colorname = string_CreateFromData(desc->next->str,
desc->next->len);
curmode.color = x_string_to_color(colorname, default_fgcolor);
free(colorname);
curmode.expcolor = 1;
/* skip over the rest of the @font */
desc = desc->next->next;
}
} else if (desc->len > 0) { /* avoid @{...} */
free(curmode.substyle);
if (curmode.font) {
free(curmode.font);
curmode.font = NULL;
}
curmode.substyle = string_CreateFromData(desc->str, desc->len);
}
break;
case DT_STR:
auxblocks[nextblock].align = curmode.align;
auxblocks[nextblock].font = mode_to_font(dpy, style, &curmode);
auxblocks[nextblock].str = desc->str;
auxblocks[nextblock].len = desc->len;
i = ZTransliterate(desc->str, desc->len,
strcmp(notice_charset, "UNKNOWN") ?
notice_charset : "ISO-8859-1",
#ifdef X_HAVE_UTF8_STRING
"UTF-8",
#else
"UTF-16BE",
#endif
&blocks[nextblock].wstr,
&blocks[nextblock].wlen);
if (i) {
var_set_variable("error", strerror(i));
#ifdef X_HAVE_UTF8_STRING
blocks[nextblock].wlen = desc->len;
blocks[nextblock].wstr = strdup(desc->str);
#else
blocks[nextblock].wlen = desc->len * 2;
blocks[nextblock].wstr = malloc(blocks[nextblock].wlen);
for (i = 0; i < desc->len; i++)
*(short *)&(blocks[nextblock].wstr[i * 2]) = htons((short)(unsigned char)desc->str[i]);
/* XXX */
#endif
}
#ifndef X_HAVE_UTF8_STRING
blocks[nextblock].wlen /= 2;
#endif
if (curmode.expcolor)
blocks[nextblock].fgcolor = curmode.color;
else
blocks[nextblock].fgcolor =
x_string_to_color(mode_to_colorname(dpy, style, &curmode),
default_fgcolor);
nextblock++;
break;
case DT_END:
free(curmode.substyle);
curmode = xmode_stack_top(modes);
xmode_stack_pop(modes);
break;
case DT_NL:
lines[line].startblock = linestart;
lines[line].numblock = nextblock-linestart;
font = mode_to_font(dpy, style, &curmode);
fse = XExtentsOfFontSet(font);
lines[line].ascent = -fse->max_logical_extent.y;
lines[line].descent = fse->max_logical_extent.y +
fse->max_logical_extent.height;
line++;
linestart = nextblock;
break;
}
}
/* case DT_EOF: will drop through to here. */
if (linestart != nextblock) {
lines[line].startblock = linestart;
lines[line].numblock = nextblock-linestart;
font = mode_to_font(dpy, style, &curmode);
lines[line].ascent = 0;
lines[line].descent = 0;
line++;
}
free(curmode.substyle);
fixup_and_draw(dpy, style, auxblocks, blocks, nextblock, lines, line,
beepcount);
free(lines);
free(auxblocks);
if (free_style)
free(style);
}
static void
xhandleevent(Display *dpy,
Window w,
XEvent *event)
{
XPointer gramp; /* Avoid strict aliasing violation */
x_gram *gram;
if (XFindContext(dpy, w, desc_context, &gramp))
return;
gram = (x_gram *)gramp;
if (event->type == Expose)
x_gram_expose(dpy, w, gram,&(event->xexpose));
else
xcut(dpy, event, desc_context);
XFlush(dpy);
}
void
x_get_input(Display *dpy)
{
XEvent event;
dprintf1("Entering x_get_input(%lx).\n",(unsigned long)dpy);
/*
* Kludge to get around lossage in XPending:
*
* (the problem: XPending on a partial packet returns 0 without
* reading in the packet. This causes a problem when the X server
* dies in the middle of sending a packet.)
*/
if (XPending(dpy)==0)
XNoOp(dpy); /* Ensure server is still with us... */
while (XPending(dpy)) {
XNextEvent(dpy,&event);
xhandleevent(dpy, event.xany.window, &event);
}
}
#ifdef CMU_ZWGCPLUS
void
plus_window_deletions(ZNotice_t *notice)
{
x_gram *tmp, *fry;
char *val;
int done;
static char class_nm[NAMESIZE], instance_nm[NAMESIZE], recip_nm[NAMESIZE];
if (!x_dpy)
return;
val = var_get_variable("delete_window");
#ifdef DEBUG_DELETION
fprintf(stderr, "delete_window(%s)\n", val);
#endif
if (val) {
if (!strcmp(val, "this")) {
do {
done = 1;
tmp = bottom_gram;
while (tmp) {
if (tmp->notice == notice) {
fry = tmp;
tmp = tmp->above;
xdestroygram(x_dpy, fry->w, desc_context, fry);
done = 0;
} else {
tmp = tmp->above;
}
}
} while (!done);
}
else if (!strcmp(val, "s")) {
/* I cheated. This is really sender, not class */
strcpy(class_nm, notice->z_sender);
do {
done = 1;
tmp = bottom_gram;
while (tmp) {
if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_sender, class_nm)) {
fry = tmp;
tmp = tmp->above;
xdestroygram(x_dpy, fry->w, desc_context, fry);
done = 0;
} else {
tmp = tmp->above;
}
}
} while (!done);
}
else if (!strcmp(val, "ns")) {
/* I cheated. This is really sender, not class */
strcpy(class_nm, notice->z_sender);
do {
done = 1;
tmp = bottom_gram;
while (tmp) {
if (!!strcasecmp(((ZNotice_t *)(tmp->notice))->z_sender, class_nm)) {
fry = tmp;
tmp = tmp->above;
xdestroygram(x_dpy, fry->w, desc_context, fry);
done = 0;
} else {
tmp = tmp->above;
}
}
} while (!done);
}
else if (!strcmp(val, "r")) {
strcpy(recip_nm, notice->z_recipient);
do {
done = 1;
tmp = bottom_gram;
while (tmp) {
if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) {
fry = tmp;
tmp = tmp->above;
xdestroygram(x_dpy, fry->w, desc_context, fry);
done = 0;
} else {
tmp = tmp->above;
}
}
} while (!done);
}
else if (!strcmp(val, "nr")) {
strcpy(recip_nm, notice->z_recipient);
do {
done = 1;
tmp = bottom_gram;
while (tmp) {
if (!!strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) {
fry = tmp;
tmp = tmp->above;
xdestroygram(x_dpy, fry->w, desc_context, fry);
done = 0;
} else {
tmp = tmp->above;
}
}
} while (!done);
}
else if (!strcmp(val, "cir")) {
strcpy(class_nm, notice->z_class);
strcpy(instance_nm, notice->z_class_inst);
strcpy(recip_nm, notice->z_recipient);
do {
done = 1;
tmp = bottom_gram;
while (tmp) {
if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class_inst, instance_nm)
&& !strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm)
&& !strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm))
{
fry = tmp;
tmp = tmp->above;
xdestroygram(x_dpy, fry->w, desc_context, fry);
done = 0;
} else {
tmp = tmp->above;
}
}
} while (!done);
}
else if (!strcmp(val, "ci")) {
strcpy(class_nm, notice->z_class);
strcpy(instance_nm, notice->z_class_inst);
do {
done = 1;
tmp = bottom_gram;
while (tmp) {
if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class_inst, instance_nm)
&& !strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm))
{
fry = tmp;
tmp = tmp->above;
xdestroygram(x_dpy, fry->w, desc_context, fry);
done = 0;
} else {
tmp = tmp->above;
}
}
} while (!done);
}
else if (!strcmp(val, "cr")) {
strcpy(class_nm, notice->z_class);
strcpy(recip_nm, notice->z_recipient);
do {
done = 1;
tmp = bottom_gram;
while (tmp) {
if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm) &&
!strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm))
{
fry = tmp;
tmp = tmp->above;
xdestroygram(x_dpy, fry->w, desc_context, fry);
done = 0;
} else {
tmp = tmp->above;
}
}
} while (!done);
}
else if (!strcmp(val, "c")) {
strcpy(class_nm, notice->z_class);
do {
done = 1;
tmp = bottom_gram;
while (tmp) {
if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm)) {
fry = tmp;
tmp = tmp->above;
xdestroygram(x_dpy, fry->w, desc_context, fry);
done = 0;
} else {
tmp = tmp->above;
}
}
} while (!done);
}
else if (!strcmp(val, "all")) {
while (bottom_gram) {
xdestroygram(x_dpy, bottom_gram->w, desc_context, bottom_gram);
}
}
}
}
#endif
#endif /* X_DISPLAY_MISSING */

267
zwgc/zephyr.c Normal file
View File

@ -0,0 +1,267 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <sysdep.h>
#if (!defined(lint) && !defined(SABER))
static const char rcsid_zephyr_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* Module containing code dealing with zephyr: */
/* */
/****************************************************************************/
#include <zephyr/zephyr.h>
#include <sys/socket.h>
#include "new_string.h"
#include "zephyr.h"
#include "error.h"
#include "mux.h"
#include "subscriptions.h"
#include "variables.h"
#include "pointer.h"
#include "main.h"
#ifndef X_DISPLAY_MISSING
#include "X_driver.h"
#endif
#ifdef CMU_ZWGCPLUS
#include "plus.h"
#endif
#ifdef DEBUG
extern int zwgc_debug;
#endif /* DEBUG */
static int zephyr_inited = 0;
static unsigned short zephyr_port = 0;
/*
* Internal Routine:
*
* string get_zwgc_port_number_filename()
* Effects: Returns the filename that the zwgc port # is/should be
* stored in, based on the user's uid & the environment
* variable WGFILE. The returned string points into a
* static buffer that may change on further calls to this
* routine or getenv. The returned string should not be
* modified in any way.
*/
static string
get_zwgc_port_number_filename(void)
{
static char buffer[40];
char *temp;
temp = getenv("WGFILE");
if (temp)
return(temp);
else {
sprintf(buffer, "/tmp/wg.%d", getuid());
return(buffer);
}
}
/*
* Write out the port number to the wg file.
*/
void
write_wgfile(void)
{
char *name = get_zwgc_port_number_filename();
FILE *port_file;
port_file = fopen(name, "w");
if (port_file) {
fprintf(port_file, "%d\n", zephyr_port);
fclose(port_file);
} else {
fprintf(stderr, "zwgc: error while opening %s for writing: ", name);
perror("");
}
}
/*
*
*/
struct notice_handler_ptr {
void (*notice_handler)(ZNotice_t *);
};
static void
handle_zephyr_input(struct notice_handler_ptr *nhp)
{
ZNotice_t *notice;
struct sockaddr_in from;
int complete_packets_ready;
for (;;) {
errno = 0;
if ( (complete_packets_ready=ZPending()) < 0 )
FATAL_TRAP( errno, "while calling ZPending()" );
if (complete_packets_ready==0)
return;
notice = malloc(sizeof(ZNotice_t));
TRAP( ZReceiveNotice(notice, &from), "while getting zephyr notice" );
if (!error_code) {
notice->z_auth = ZCheckAuthentication(notice, &from);
nhp->notice_handler(notice);
}
#ifdef CMU_ZWGCPLUS
if (get_list_refcount(notice) <= 0) {
/* no windows created */
if (!get_notice_fake(notice))
list_del_notice(notice);
}
#endif
}
}
/*
*
*/
void zephyr_init(void (*notice_handler)(ZNotice_t *))
{
struct notice_handler_ptr *nhp;
char *temp;
char *exposure;
char *tty = NULL;
FILE *port_file;
/*
* Initialize zephyr. If error, print error message & exit.
*/
nhp = malloc(sizeof(struct notice_handler_ptr));
if (!nhp) {
fprintf(stderr, "Out of memory setting up zephyr notice handler.\n");
exit(3);
}
FATAL_TRAP( ZInitialize(), "while initializing Zephyr" );
FATAL_TRAP( ZOpenPort(&zephyr_port), "while opening Zephyr port" );
/*
* Save away our port number in a special place so that zctl and
* other clients can send us control messages: <<<>>>
*/
temp = get_zwgc_port_number_filename();
port_file = fopen(temp, "r");
if (port_file) {
fprintf(stderr, "zwgc: windowgram file already exists. If you are\n");
fprintf(stderr, "zwgc: not already running zwgc, delete %s\n", temp);
fprintf(stderr, "zwgc: and try again.\n");
exit(1);
}
write_wgfile();
/* Set hostname and tty for locations. If we support X, use the
* display string for the default tty name. */
if (location_override)
tty = location_override;
#ifndef X_DISPLAY_MISSING
else if (x_dpy)
tty = DisplayString(x_dpy);
#endif
error_code = ZInitLocationInfo(NULL, tty);
TRAP( error_code, "while initializing location information" );
/*
* Retrieve the user's desired exposure level (from the zephyr variable
* "exposure"), convert it to the proper internal form then
* set the user's location using it. If the exposure level is
* not one of the allowed ones, print an error and treat it as
* EXPOSE_NONE.
*/
temp = ZGetVariable("exposure");
if (temp) {
if (!(exposure = ZParseExposureLevel(temp))) {
ERROR2("invalid exposure level %s, using exposure level none instead.\n", temp);
exposure = EXPOSE_NONE;
}
} else
exposure = EXPOSE_OPSTAFF;
error_code = ZSetLocation(exposure); /* <<<>>> */
if (error_code != ZERR_LOGINFAIL)
TRAP( error_code, "while setting location" );
/*
* If the exposure level isn't EXPOSE_NONE, turn on recieving notices.
* (this involves reading in the subscription file, etc.)
*/
if (string_Neq(exposure, EXPOSE_NONE))
zwgc_startup();
/*
* Set $realm to our realm and $user to our zephyr username:
*/
var_set_variable("realm", (char *)ZGetRealm()); /* XXX should propagate the
* const */
var_set_variable("user", ZGetSender());
/*
* <<<>>>
*/
nhp->notice_handler = notice_handler;
mux_add_input_source(ZGetFD(), (void (*)(void *))handle_zephyr_input, nhp);
zephyr_inited = 1;
return;
}
/*
*
*/
void finalize_zephyr(void) /* <<<>>> */
{
string temp;
if (zephyr_inited) {
/*
* Remove the file containing our port # since it is no longer needed:
*/
errno = 0;
temp = get_zwgc_port_number_filename();
unlink(temp);
if (errno) {
fprintf(stderr, "zwgc: error while trying to delete %s: ", temp);
perror("");
}
/*
* Cancel our subscriptions, unset our location, and close our zephyr
* connection:
*/
#ifdef DEBUG
if (zwgc_debug) {
TRAP( ZUnsetLocation(), "while unsetting location" );
TRAP( ZCancelSubscriptions(0), "while canceling subscriptions" );
} else {
#endif /* DEBUG */
(void) ZUnsetLocation();
(void) ZCancelSubscriptions(0);
#ifdef DEBUG
}
#endif /* DEBUG */
ZClosePort();
}
return;
}

26
zwgc/zephyr.h Normal file
View File

@ -0,0 +1,26 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifndef zephyr_MODULE
#define zephyr_MODULE
#include <zephyr/zephyr.h>
extern void zephyr_init(void(*)(ZNotice_t *));
extern void finalize_zephyr(void);
extern void write_wgfile(void);
#endif

1067
zwgc/zwgc.1.in Normal file

File diff suppressed because it is too large Load Diff

136
zwgc/zwgc.desc Normal file
View File

@ -0,0 +1,136 @@
# Copyright 1989, 1990 Massachusetts Institute of Technology
#
# For copying and distribution information, see the file
# "mit-copyright.h".
#
# $Id$
#
#
# Default WindowGram description file
#
# Opcode "ping" is used by sender programs to see if the message would
# really get sent, or if the recipient has logged out. No useful
# information is normally contained in these messages, so we discard them.
if (upcase($opcode) == "PING") then exit endif
#
# AUTHENTICATION information
#
# $auth can be either Yes, No, or Forged
#
# "Yes" means that the sender field present in the notice was verified by
# Kerberos authentication
#
# "No" means that either the sender did not include any authentication
# information, or the authentication information was not verified by the
# Zephyr Server before the notice was sent to you.
#
# "Forged" means that the Server claims that the sender of the notice
# was verified by Kerberos authentication, but your WindowGram client
# could not verify this. This stage of verification is done by a cryptographic
# checksum. The most probable cause of the failure of the checksum
# provided by the Server to match the checksum generated by your
# WindowGram client is that you changed Kerberos tickets, and the Server
# was using an old value to compute the cryptographic checksum. You can
# update the Server's value by typing 'zctl load' to your prompt.
#
# By default, notices which appear forged are labeled as 'UNAUTHENTIC'
# to avoid confusion as to what 'Forged' really means.
# To change this display, change the last word in the line following
# 'match "forged" to something other than "UNAUTHENTIC".
case $auth
match "yes"
set aval = "Authentic"
match "no","forged"
set aval = "@b(@large(UNAUTHENTIC))"
endcase
case $class
match "WG_CTL_CLASS"
exit
match "message"
if (downcase($recipient) == downcase($user)) then
case $instance
match "PERSONAL"
set type = "Personal"
match "URGENT"
set type = "Urgent"
default
set type = $instance
endcase
else
set type = "Instance "+$instance
endif
if ($number_of_fields == "1") then
fields body
set signature = ""
else
fields signature body
endif
if ($signature =~ "^[Ff]rom: .*") then
set dummy = lany($signature,"From: ")
endif
if ($signature =~ "\n$") then
set dummy = rany($signature,"\n")
endif
if ($signature == "") then
set ftext = "From: @bold("+protect($sender)+")"
else
set ftext = "From: @bold(@{"+protect($signature)+"} <"+
protect($sender)+">)"
endif
print "@center(@bold("+$aval+") "+$type+" message at "+$time+
" on "+$date+"\n"+$ftext+" on "+$fromhost+"\nTo: "+
$recipient+")\n\n"
print $body
put
exit
match "login"
case $opcode
match "USER_LOGIN"
set log = "logged in"
match "USER_LOGOUT"
set log = "logged out"
default
set log = "unknown opcode"
endcase
fields host when tty
print "@center(@bold("+$sender+") "+$log+")\n"
print "@center(on @bold("+$host+") on "+$tty+")\n"
print "@center(at "+$when+")"
put
exit
default
if (downcase($class) == "filsys" and downcase($opcode) == "shutdown") then
set format = "From $sender:\n@bold(Shutdown message from $1 at $time)\n"+
"@center(System going down, message is:)\n\n$2\n\n@center(@bold($3))"
elseif (downcase($class) == "filsys") then
set format = "@bold(Filesystem Operation Message for $instance:)\n"+
"From: @bold($sender) at $time $date\n$message"
elseif (downcase($class) == "mail" and downcase($instance) == "popret") then
set format = "You have new mail:\n\nFrom: $1\nTo: $2\nSubject: $3"
elseif (downcase($class) == "mail") then
set format = "From Post Office $1:\n$2"
elseif (downcase($class) == "syslog") then
set format = "From $sender:\nSyslog message from $instance, level "+
"$opcode:\n$message"
elseif ($number_of_fields == "1") then
set format = "Class $class, Instance $instance:\nTo: @bold($recipient) "+
"at $time $date\nFrom: @bold($sender)\n\n$message"
else
set format = "Class $class, Instance $instance:\nTo: @bold($recipient) "+
"at $time $date\nFrom: @bold($1) <$sender>\n\n$2"
endif
print "(Authentication: @bold("+$aval+") from host: "+$fromhost+")\n"
print substitute($format)
put
exit
endcase

184
zwgc/zwgc.el Normal file
View File

@ -0,0 +1,184 @@
; zwgc.el
;
; This file is part of the Project Athena Zephyr Notification System.
; Created by: Mark W. Eichin <eichin@athena.mit.edu>
; $Id$
; Copyright (c) 1988 by the Massachusetts Institute of Technology.
; For copying and distribution information, see the file
; "mit-copyright.h".
;
; Emacs mode for running zwgc in a sub process of emacs. It pops up a
; window for every new message; if you make bells appear between each
; message, it will be able to seperate them. If you move the mouse
; into the message window and hit `delete' it will delete the current
; message; if there are other messages, it will show them, if not, it
; will make the window go away.
;
; Invoke with M-x zwgc.
;
; Also included is M-x zsend, which prompts for a user name and a
; message to send to them. If the message is blank, a buffer is popped
; up to edit the message in. If a prefix argument is given, zsend
; prompts for an instance instead. If the user name is blank, the last
; one is reused.
;
; The following should be added to your .zephyr.desc file if you want
; to take advantage of the zwgc message seperation features:
; does $mode
; match tty
; beep
; endmatch
; enddoes
;
(defvar zwgc_el-RCS-id)
(setq zwgc_el-RCS-id "$Id$")
;
;
(defun narrow-to-string (str)
"narrow and put up a string..."
(interactive "sString: ")
(narrow-to-region (point) (point))
(insert str))
(defvar zwgc-prog "/usr/etc/zwgc"
"*Program to run as the zwgc process. Should set it for the machine type.")
(defun zwgc-wakeup (proc string)
"Procedure called when zwgc spits something out"
(let (start-limit)
(save-excursion (set-buffer (get-buffer "*zwgc*"))
(setq start-limit (point))
(goto-char (point-max))
(if (= 7 (string-to-char string))
(progn
(ding 1)
(message "got one!")
(narrow-to-string string))
(insert string))
(search-backward "\007" start-limit t)
(while (search-forward "\015" (point-max) t) ;flush ^M's
(delete-backward-char 1)))
(Special-pop-up-window (get-buffer "*zwgc*"))
))
(defun zwgc ()
"emacs mode for running zwgc in a sub process of emacs. It pops up a
window for every new message; if you make bells appear between each
message, it will be able to seperate them. If you move the mouse into
the message window and hit `delete' it will delete the current
message; if there are other messages, it will show them, if not, it
will make the window go away."
(interactive)
(require 'shell)
(let ((buffer (get-buffer-create "*zwgc*")) proc status)
(setq proc (get-buffer-process buffer))
(if proc
(setq status (process-status proc)))
(save-excursion
(set-buffer buffer)
(if (memq status '(run stop))
nil
(if proc (delete-process proc))
(setq proc (start-process "Zwgc" buffer
zwgc-prog "-disable" "X"
"-default" "plain" "-nofork"))
(set-process-filter proc 'zwgc-wakeup))
(shell-mode)
(local-set-key "\177" 'zwgc-punt)
)
))
(defun Special-pop-up-window (buffer &optional max-height)
"Pop up a window that is just big enough to hold the current buffer."
(interactive "bBuffer to pop: ")
(let* ((retwin (selected-window))
(pop-up-windows t)
(window-min-height 1))
(pop-to-buffer buffer)
(setq lines (1+ (count-lines (point-min) (point-max))))
(enlarge-window (- lines (window-height (selected-window))))
(goto-char (point-min))
(other-window 1)
))
(defun zwgc-punt ()
"Delete the current ZephyrGram from the *zwgc* buffer."
(interactive)
(let ((window-min-height 1))
(display-buffer (get-buffer "*zwgc*"))
(delete-region (point-min) (point-max))
(widen)
(if (not (search-backward "\007" nil t))
(delete-windows-on "*zwgc*")
(narrow-to-region (point) (point-max))
(enlarge-window (- (1+ (count-lines (point-min) (point-max)))
(window-height (selected-window))))
(goto-char (point-min))
)))
;;
;; [eichin:19880309.2005EST]
;; zsend.el
;; Send zephyrgrams from emacs...
;;
(defvar *who* "" "last user sent to with zsend")
(defun zsend (&optional who message)
"zsend prompts for a user name and a message to send to them as a
ZephyrGram. If the message is blank, a buffer is popped up to edit the
message in. If a prefix argument is given, zsend prompts for an
instance instead. If the user name is blank, the last one is reused."
(interactive
(list (if current-prefix-arg ; is this portable???
(cons 'instance (read-input "Instance:"))
(cons 'who (read-input "Who:")))
; (select-window (minibuffer-window))
; (enlarge-window 4)
(read-input "Message:")))
(save-excursion
(let ((tempbuf (get-buffer-create " *zephyr*send*")))
(switch-to-buffer tempbuf)
(local-set-key "\C-c\C-c" 'exit-recursive-edit)
(erase-buffer)
(if (and (equal (cdr who) "")
(equal *who* ""))
(message "Please specify user at least once.")
(if (not (equal (cdr who) ""))
(setq *who* who) ; save *who* for next time
(setq who *who*)) ; or, use the old value
(if (not (equal message ""))
(progn
(insert message)
(zwrite who))
(progn
(recursive-edit)
(zwrite who)))))))
(defun zwrite (who)
"Send a ZephyrGram to user WHO, zsend is the user interface to this."
(if (eq 'who (car who))
(call-process-region (point-min) (point-max) ;range
"/usr/athena/zwrite" ;process
t ;delete-p
t ;output-p
nil ;redisplay-p
"-q" ;args -- ignore server responses.
(cdr who))
(call-process-region (point-min) (point-max) ;range
"/usr/athena/zwrite" ;process
t ;delete-p
t ;output-p
nil ;redisplay-p
"-q" ;args -- ignore server responses.
"-i" ;[eichin:19880312.0015EST]
(cdr who)))
(if (not (equal (point-max) 1))
(message (buffer-substring 1 (1- (point-max))))))
; suggested binding (control-meta-z)
;(global-set-key "\M-\C-z" 'zsend)

28
zwgc/zwgc.h Normal file
View File

@ -0,0 +1,28 @@
/* This file is part of the Project Athena Zephyr Notification System.
* It is one of the source files comprising zwgc, the Zephyr WindowGram
* client.
*
* Created by: Marc Horowitz <marc@athena.mit.edu>
*
* $Id$
*
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
* For copying and distribution information, see the file
* "mit-copyright.h".
*/
#include <zephyr/mit-copyright.h>
#ifdef DEBUG
extern int zwgc_debug;
#define dprintf(x) if (zwgc_debug) printf(x)
#define dprintf1(x,y) if (zwgc_debug) printf(x,y)
#else
#define dprintf(x)
#define dprintf1(x,y)
#endif

102
zwgc/zwgc_resources Normal file
View File

@ -0,0 +1,102 @@
! Copyright 1989 Massachusetts Institute of Technology
!
! For copying and distribution information, see the file
! "mit-copyright.h".
!
! $Id$
!
!
! Zwgc application specific global resources:
!
*style*substyle.default.fontfamily: default
*style.message.personal*substyle.title.fontfamily: huge
*style*geometry: +0+0
!
! The following is the adobe-courier font family. Availiable sizes are
! 80, 100, 120, 140, 180, and 240. This family used to be courier.
!
*fontfamily.default.small.roman: *-courier-medium-r-*-80-*-m-*,*
*fontfamily.default.small.bold: *-courier-bold-r-*-80-*-m-*,*
*fontfamily.default.small.italic: *-courier-medium-o-*-80-*-m-*,*
*fontfamily.default.small.bolditalic: *-courier-bold-o-*-80-*-m-*,*
*fontfamily.default.medium.roman: *-courier-medium-r-*-120-*-m-*,*
*fontfamily.default.medium.bold: *-courier-bold-r-*-120-*-m-*,*
*fontfamily.default.medium.italic: *-courier-medium-o-*-120-*-m-*,*
*fontfamily.default.medium.bolditalic: *-courier-bold-o-*-120-*-m-*,*
*fontfamily.default.large.roman: *-courier-medium-r-*-240-*-m-*,*
*fontfamily.default.large.bold: *-courier-bold-r-*-240-*-m-*,*
*fontfamily.default.large.italic: *-courier-medium-o-*-240-*-m-*,*
*fontfamily.default.large.bolditalic: *-courier-bold-o-*-240-*-m-*,*
!
! The following is the adobe-courier font family. Availiable sizes are
! 80, 100, 120, 140, 180, and 240. This family used to be courier.
!
*fontfamily.courier.small.roman: *-courier-medium-r-*-80-*-m-*,*
*fontfamily.courier.small.bold: *-courier-bold-r-*-80-*-m-*,*
*fontfamily.courier.small.italic: *-courier-medium-o-*-80-*-m-*,*
*fontfamily.courier.small.bolditalic: *-courier-bold-o-*-80-*-m-*,*
*fontfamily.courier.medium.roman: *-courier-medium-r-*-120-*-m-*,*
*fontfamily.courier.medium.bold: *-courier-bold-r-*-120-*-m-*,*
*fontfamily.courier.medium.italic: *-courier-medium-o-*-120-*-m-*,*
*fontfamily.courier.medium.bolditalic: *-courier-bold-o-*-120-*-m-*,*
*fontfamily.courier.large.roman: *-courier-medium-r-*-240-*-m-*,*
*fontfamily.courier.large.bold: *-courier-bold-r-*-240-*-m-*,*
*fontfamily.courier.large.italic: *-courier-medium-o-*-240-*-m-*,*
*fontfamily.courier.large.bolditalic: *-courier-bold-o-*-240-*-m-*,*
!
! The following is the adobe-times font family. Availiable sizes are
! 80, 100, 120, 140, 180, and 240. This family used to be times-roman.
!
*fontfamily.times.small.roman: *-times-medium-r-*-80-*-p-*,*
*fontfamily.times.small.bold: *-times-bold-r-*-80-*-p-*,*
*fontfamily.times.small.italic: *-times-medium-i-*-80-*-p-*,*
*fontfamily.times.small.bolditalic: *-times-bold-i-*-80-*-p-*,*
*fontfamily.times.medium.roman: *-times-medium-r-*-120-*-p-*,*
*fontfamily.times.medium.bold: *-times-bold-r-*-120-*-p-*,*
*fontfamily.times.medium.italic: *-times-medium-i-*-120-*-p-*,*
*fontfamily.times.medium.bolditalic: *-times-bold-i-*-120-*-p-*,*
*fontfamily.times.large.roman: *-times-medium-r-*-240-*-p-*,*
*fontfamily.times.large.bold: *-times-bold-r-*-240-*-p-*,*
*fontfamily.times.large.italic: *-times-medium-i-*-240-*-p-*,*
*fontfamily.times.large.bolditalic: *-times-bold-i-*-240-*-p-*,*
!
! The following is the adobe-helvetica font family. Availiable sizes are
! 80, 100, 120, 140, 180, and 240. This family used to be helvetica.
!
*fontfamily.helvetica.small.roman: *-helvetica-medium-r-*-80-*-p-*,*
*fontfamily.helvetica.small.bold: *-helvetica-bold-r-*-80-*-p-*,*
*fontfamily.helvetica.small.italic: *-helvetica-medium-o-*-80-*-p-*,*
*fontfamily.helvetica.small.bolditalic: *-helvetica-bold-o-*-80-*-p-*,*
*fontfamily.helvetica.medium.roman: *-helvetica-medium-r-*-120-*-p-*,*
*fontfamily.helvetica.medium.bold: *-helvetica-bold-r-*-120-*-p-*,*
*fontfamily.helvetica.medium.italic: *-helvetica-medium-o-*-120-*-p-*,*
*fontfamily.helvetica.medium.bolditalic:*-helvetica-bold-o-*-120-*-p-*,*
*fontfamily.helvetica.large.roman: *-helvetica-medium-r-*-240-*-p-*,*
*fontfamily.helvetica.large.bold: *-helvetica-bold-r-*-240-*-p-*,*
*fontfamily.helvetica.large.italic: *-helvetica-medium-o-*-240-*-p-*,*
*fontfamily.helvetica.large.bolditalic: *-helvetica-bold-o-*-240-*-p-*,*
!
! Quick hack...
!
*fontfamily.huge*roman: *-charter-medium-r-*-33-*-p-*,*
*fontfamily.huge*bold: *-charter-bold-r-*-33-*-p-*,*
*fontfamily.huge*italic: *-charter-medium-i-*-33-*-p-*,*
*fontfamily.huge*bolditalic: *-charter-bold-i-*-33-*-p-*,*