[comp.sources.x] v07i021: AWL -- layout language for widget hierarchies, Part07/17

vixie@wrl.dec.com (Paul Vixie) (05/03/90)

Submitted-by: vixie@wrl.dec.com (Paul Vixie)
Posting-number: Volume 7, Issue 21
Archive-name: awl/part07

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 7 (of 17)."
# Contents:  convert.c etc/strsed.3c macros.h
# Wrapped by vixie@jove.pa.dec.com on Mon Apr 30 01:25:22 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'convert.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'convert.c'\"
else
echo shar: Extracting \"'convert.c'\" \(16995 characters\)
sed "s/^X//" >'convert.c' <<'END_OF_FILE'
X#ifndef lint
static char *rcsid = "$Header: /usr/src/local/awl/RCS/convert.c,v 2.4 90/04/19 20:04:48 jkh Exp $";
X#endif
X
X/*
X *
X *                     Copyright 1990
X *                    Jordan K. Hubbard
X *
X *		  PCS Computer Systeme, GmbH.
X *	             Munich, West Germany
X *
X *
X * This file is part of AWL.
X *
X * AWL is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 1, or (at your option)
X * any later version.
X *
X * AWL is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with AWL; see the file COPYING.  If not, write to
X * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
X *
X *
X */
X
X/*
X * Various utilities for converting between types.
X *
X * $Log:	convert.c,v $
X * Revision 2.4  90/04/19  20:04:48  jkh
X * Alpha checkin.
X * 
X * Revision 2.3  90/03/31  06:54:44  jkh
X * Fixed bad error message in CALLBACK convert.
X * 
X * Revision 2.2  90/03/29  18:27:37  jkh
X * Fixed a lot more bugs with (PIXMAP) conversion.
X * 
X * Revision 2.1  90/03/27  08:58:56  jkh
X * Added PIXMAP conversion, moved do_convert() over from evalutils.c
X * 
X * Revision 2.0  90/03/26  01:44:15  jkh
X * pre-beta check-in
X * 
X */
X
X#include "AwlP.h"
X#include "y.tab.h"
X
X/* This will lose on non-ascii architectures. I don't really care. */
X#define DIGIT(x)        (isdigit(x) ? (x) - '0' : \
X			 islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
X
Local char oct[] = "01234567";
X
X/* determine whether a digit is valid for a given type/default radix */
XExport Boolean isValidDigit(aw, ch, type)
AwlWidget aw;
char ch;
int type;
X{
X#ifndef toupper
X     Import char toupper();
X#endif
X
X     /* sign char is valid for everyone */
X     if (ch == '+' || ch == '-')
X	  return(TRUE);
X     /* next, check less restrictive float/any */
X     else if ((ch == '.' || toupper(ch) == 'E' || isdigit(ch))
X	 && (type == FLOAT || type == ANY))
X	  return(TRUE);
X     /* now check integer */
X     else if (awl_radix(aw) == 8 ? (int)index(oct, ch) :
X	      awl_radix(aw) == 16 ? isxdigit(ch) : isdigit(ch))
X	  return(TRUE);
X     return(FALSE);
X}
X
X/* Given a string, return an integer (doing any necessary base conversion) */
XExport int atonum(aw, s, base)
AwlWidget aw;
char *s;
int base;
X{
X     int value = 0;
X     int sign = -1;
X
X     if (awl_radix(aw) == 0)
X	  awl_radix(aw) = 10;
X
X     if (base == 0)	/* set a default */
X	  base = awl_radix(aw);
X
X     if (!s || !strlen(s))
X	  return(0);
X
X     s = skip_whitespace(s);
X
X     if (*s == '-') {
X	  s++;
X	  sign = 1;
X     }
X     else if (*s == '+') {
X	  s++;
X	  sign = -1;
X     }
X     /* skip the 0x digits */
X     if (base == 16) {
X	  if (!strncmp(s, "0x", 2) || !strncmp(s, "0X", 2))
X	       s += 2;
X	  else
X	       return(0);
X     }
X     while (*s && ((base == 8 ? (int)index(oct, *s) : isdigit(*s))
X		   || (base == 16 && isxdigit(*s)))) {
X	  value = base * value - DIGIT(*s);
X	  s++;
X     }
X     return(value * sign);
X}
X
X/*
X * Given a number, convert it to its string representation. Returned
X * string is static and should be saved by the caller.
X */
XExport String numtoa(aw, i, base)
AwlWidget aw;
int i, base;
X{
X     Local char a[32];
X
X     if (awl_radix(aw) == 0)
X	  awl_radix(aw) = 10;
X
X     if (base == 0)
X	  base = awl_radix(aw);
X
X     switch(base) {
X     case 8:
X	  sprintf(a, "%#o", i);
X	  break;
X
X     case 10:
X	  sprintf(a, "%d", i);
X	  break;
X
X     case 16:
X     default:
X	  sprintf(a, "%#0x", i);
X	  break;
X     }
X     return(a);
X}
X
X/*
X * Given a float, convert it to its string representation.
X */
XExport String ftoa(f)
float f;
X{
X     Local char a[64];
X
X     sprintf(a, "%g", f);
X     return(a);
X}
X
X/*
X * This is the "top level" conversion routine. It handles type conversion
X * in one of three ways: If the type is one of awl's internal types (like
X * INT or FLOAT), it uses awl's internal coercion routine that's used for
X * implicit coercion operations. If type is not one of awl's internal
X * types but is one of the "special toolkit types", it handles it directly.
X * Finally, if it's nothing awl knows about, it calls another routine that
X * tries to convert it with the toolkit's type conversion mechanism.
X */
XExport Value do_convert(aw, a1, a2)
AwlWidget aw;
Value a1, a2;
X{
X     Value res;
X     int type, fail;
X
X     /*
X      * Conversion type can be specified in several ways:
X      * If it's an INT type, then we presume that it's one of our
X      * predefined internal types and try to deal with it accordingly.
X      * If it's a string, it still may be one of our internal types
X      * specified by its printname, so we try to look it up. If the string
X      * wasn't a printname for one of our times (type was returned as zero)
X      * we can then assume that it's the name of some Toolkit resource.
X      */
X     value_clear(res);
X
X     if (value_type(a2) == INT) {
X	  if (!(type = value_int(a2))) {
X	       exec_warn(aw, "Attempt to convert to type 0, ignored.");
X	       return(res);
X	  }
X     }
X     else if (value_type(a2) == STRING)
X	  type = map_resword_to_token(value_string(a2), T_TYPE);
X
X     /* is conversion even necessary? */
X     if (value_type(a1) == type)
X	  res = a1;
X
X     else switch (type) {
X     case 0:
X	  /*
X	   * Presume it's a conversion to an unknown Toolkit type. Let
X	   * convert_external() handle it.
X	   */
X	  value_set(res, DATA, ANY, any,
X		    convert_external(aw, coerce(aw, a1, ANY),
X				     value_string(a2), &fail));
X	  if (fail)
X	       exec_warn(aw, "Conversion failure for '%s'", value_string(a2));
X	  break;
X
X     case CALLBACK:
X	  if (value_type(a1) != SYMBOL ||
X	      symbol_class(value_symbol(a1)) != FUNCTION) {
X	       exec_warn(aw, "Attempt to convert non-function to CALLBACK");
X	       value_clear(res);
X	  }
X	  else {
X	       Symbol tmp = value_symbol(a1);
X	       XtCallbackRec *cb;
X
X	       cb = (XtCallbackRec *)XtMalloc(sizeof(XtCallbackRec) * 2);
X	       cb[1].callback = NULL;
X	       cb[1].closure = 0;
X	       switch(symbol_type(tmp)) {
X	       case FUNC_BUILTIN:
X	       case FUNC_USER:
X		    cb[0].callback = (XtCallbackProc)do_callback_user;
X		    cb[0].closure = (caddr_t)tmp;
X		    value_set(res, DATA, ANY, any, (Generic)cb);
X		    break;
X
X	       case FUNC_CALLBACK:
X		    cb[0].callback =
X			 (XtCallbackProc)function_faddr(symbol_function(tmp));
X		    cb[0].closure = function_data(symbol_function(tmp));
X		    value_set(res, DATA, ANY, any, (Generic)cb);
X		    break;
X
X	       case FUNC_UNDEF:
X		    exec_warn(aw, "Can't convert %s to CALLBACK; not defined",
X			      symbol_name(tmp));
X		    break;
X
X	       default:
X		    exec_warn(aw, "Can't convert function type %s to CALLBACK",
X			      type_name(symbol_type(tmp)));
X		    value_clear(res);
X		    break;
X	       }
X	  }
X	  break;
X
X     case PIXMAP:
X	  a1 = coerce(aw, a1, LIST);
X	  if (!awl_ctable(aw))
X	       exec_warn(aw, "No color table installed! No conversion done.");
X	  else if (!list_is_rect(value_list(a1)))
X	       exec_warn(aw, "Non-rectangular list for PIXMAP conversion.");
X	  else if (strlen(value_list(a1)[0]) % ctab_nchars(awl_ctable(aw)))
X	       exec_warn(aw, "List uneven for color table of %d chars/pixel.");
X	  else {
X	       Pixmap ret;
X	       char cmap[32]; /* the largest we can expect, see xtkrtns.c */
X	       int height, width, scanlen, nch, x, y;
X	       String *l = value_list(a1);
X	       CTable ct = awl_ctable(aw);
X	       Pixel pix;
X	       char *data;
X	       XImage *img;
X
X	       scanlen = strlen(l[0]);
X	       nch = ctab_nchars(ct);
X	       height = list_len(l);
X	       width = scanlen / nch;
X	       data = XtMalloc(height * width * 4);
X	       ret = XCreatePixmap(XtDisplay(aw), XtWindow(aw) ? XtWindow(aw) :
X				   RootWindowOfScreen(XtScreen(aw)),
X				   width, height,
X				   DefaultDepthOfScreen(XtScreen(aw)));
X	       img = XCreateImage(XtDisplay(aw),
X				  DefaultVisualOfScreen(XtScreen(aw)),
X				  DefaultDepthOfScreen(XtScreen(aw)),
X				  ZPixmap, 0, data, width, height, 32, 0);
X	       for (y = 0; y < height; y++) {
X		    for (x = 0; x < scanlen; x += nch) {
X			 strncpy(cmap, l[y] + x, nch);
X			 cmap[nch] = '\0';
X			 pix = ctab_colors(ct)[(int)hash_search(ctab_hash(ct),
X					       cmap, NULL, NULL)];
X			 XPutPixel(img, x ? x / nch : 0, y, pix);
X		    }
X	       }
X	       XPutImage(XtDisplay(aw), ret, DefaultGCOfScreen(XtScreen(aw)),
X			 img, 0, 0, 0, 0, width, height);
X	       XDestroyImage(img);
X	       value_set(res, DATA, ANY, any, (Generic)ret);
X	  }
X	  break;
X
X     case TRANSLATION:
X	  a1 = coerce(aw, a1, ANY);
X	  if (value_type(a1) != STRING) {
X	       exec_warn(aw, "Attempt to convert non-string to TRANSLATION");
X	       value_clear(res);
X	  }
X	  else {
X	       Local Boolean added_action = FALSE;
X	       int cnt, func;
X	       String src, dst;
X	       char fname[256];
X	       XtTranslations trans;
X
X	       if (!added_action) {
X		    Import void do_action_user();
X		    Local XtActionsRec do_action[] =
X			 { { "DOAWL", do_action_user } };
X
X		    XtAppAddActions(XtWidgetToApplicationContext(aw),
X				    do_action, XtNumber(do_action));
X		    added_action = TRUE;
X	       }
X	       /* first, try to figure out how much space we'll need */
X	       cnt = strlen(value_string(a1));
X	       src = value_string(a1);
X	       while (*src != '\0')
X		    if (*(src++) == ':')
X			 cnt += 6;
X	       /*
X		* Now copy the translations, converting them on-the-fly.
X		* This entails looking for all the "function" references
X		* in the translation table and converting them to function
X		* calls to the DOAWL() action. The original function name
X		* becomes the first parameter to DOAWL() with the original
X		* parameters (if any) being forwarded by DOAWL() to the
X		* real target function. If the function name is not known
X		* to awl, however, or is known to be already an ACTION
X		* function, we leave it alone.
X		*/
X	       debug(aw, "Translations before convert: %s", value_string(a1));
X	       src = value_string(a1);
X	       dst = XtMalloc(cnt + 1);
X	       cnt = 0;
X	       while (*src != '\0') {
X		    dst[cnt++] = *src;
X		    if (*(src++) == ':') {
X			 src = skip_whitespace(src);
X			 func = 0;
X			 while (*src && *src != '(')
X			      fname[func++] = *(src++);
X			 if (*(src++) != '(')
X			      exec_warn(aw, "Bad TRANSLATION, missing '('");
X			 else {
X			      Symbol tmp;
X
X			      fname[func] = '\0';
X			      tmp = symbol_find(aw, fname);
X			      if (!tmp || symbol_type(tmp) == FUNC_ACTION
X				  || symbol_class(tmp) != FUNCTION) {
X				   strcpy(dst + cnt, fname);
X				   cnt += func;
X				   dst[cnt++] = '(';
X			      }
X			      else {
X				   strcpy(dst + cnt, "DOAWL(");
X				   cnt += 6;
X				   strcpy(dst + cnt, fname);
X				   cnt += func;
X				   src = skip_whitespace(src);
X				   if (*src != ')')
X					dst[cnt++] = ',';
X			      }
X			 }
X		    }
X	       }
X	       dst[cnt] = '\0';
X 	       debug(aw, "Translations after convert: %s", dst);
X	       trans = XtParseTranslationTable(dst);
X	       XtFree(dst);
X	       value_set(res, DATA, ANY, any, (Generic)trans);
X          }
X	  break;
X
X     case WIDGET:
X	  a1 = coerce(aw, a1, ANY);
X	  if (value_type(a1) == LAYOUT) {
X	       if (wl_id(value_any(a1)))
X		    value_set(res, DATA, WIDGET, widget, wl_id(value_any(a1)));
X	       else
X		    value_set(res, INDIRECT, WIDGET, any,
X			      (Generic)&wl_id(value_any(a1)));
X	  }
X	  else /* assume they know what they're doing */
X	       value_set(res, DATA, WIDGET, any, value_any(a1));
X	  break;
X
X     case LIST:	/* special pre-prep case for LIST */
X	  if (value_type(a1) == SYMBOL
X	      && symbol_type(value_symbol(a1)) != STRING
X	      && symbol_alist(value_symbol(a1))) {
X	       String *tmp;
X
X	       tmp = list_from_alist(aw, symbol_alist(value_symbol(a1)));
X	       value_set(res, DATA, LIST, aobj, new_aobj(tmp));
X	       break;
X	  }
X
X     default:
X	  /* handle it as a standard known type */
X	  res = coerce(aw, a1, type);
X	  break;
X     }
X     return(res);
X}
X
X/*
X *
X * DANGER Will Robinson! XtConvert() hands back an address which
X * may be used in different ways depending on what we've converted.
X * We try to deal with this as best possible, but perhaps not successfully
X * in all cases. We use a fail flag to indicate failure since the returned
X * value can be zero.
X */
XExport Generic convert_external(aw, val, to_type, fail)
AwlWidget aw;
Value val;
String to_type;
int *fail;
X{
X     XrmValue from, to;
X
X     to.addr = NULL;
X     to.size = 0;
X     *fail = 0;	/* Be optimistic */
X
X     val = coerce(aw, val, ANY);
X
X     switch (value_type(val)) {
X     case STRING:
X	  from.addr = value_string(val);
X	  from.size = strlen(value_string(val)) + 1;
X	  XtConvert(aw, "String", &from, to_type, &to);
X	  break;
X	  
X     case INT:
X	  from.addr = (Generic)&(value_int(val));
X	  from.size = sizeof(int);
X	  XtConvert(aw, "Int", &from, to_type, &to);
X	  break;
X	  
X     case FLOAT:
X	  from.addr = (Generic)&(value_float(val));
X	  from.size = sizeof(FTYPE);
X	  XtConvert(aw, "Float", &from, to_type, &to);
X	  break;
X	  
X     default:
X	  to.size = 0;
X	  break;
X     }
X     if (to.size == 0 || to.addr == NULL) {
X	  *fail = 1;
X	  return(NULL);
X     }
X     if (to.size == 1)
X	  return((Generic)(*to.addr));
X     else if (to.size == 2)
X	  return((Generic)(*((XtArgVal *)to.addr)));
X     else
X	  return((Generic)(*(long *)to.addr));
X}
X
X/* Coerce val to type, returning new value */
XExport Value coerce(aw, val, type)
AwlWidget aw;
Value val;
int type;
X{
X     Value ret;
X
X     if (value_type(val) == type)
X	  return(val);
X     else
X	  val = do_load(aw, val, FALSE);
X
X     if (value_type(val) == type || type == ANY)
X	  return(val);
X
X     value_type(ret) = type;
X     value_class(ret) = value_class(val);	/* retain class */
X
X     switch (type) {
X     case CHAR:
X	  switch(value_type(val)) {
X	  case INT:
X	       value_char(ret) = value_int(val);
X	       break;
X
X	  case FLOAT:
X	       value_char(ret) = (char)value_float(val);
X	       break;
X
X	  case STRING:
X	       value_char(ret) = (char)atonum(aw, value_string(val), 0);
X	       break;
X
X	  default:
X	       value_char(ret) = (char)value_any(val);
X	       break;
X	  }
X	  break;
X
X     case INT:
X	  switch(value_type(val)) {
X	  case CHAR:
X	       value_int(ret) = value_char(val);
X	       break;
X
X	  case FLOAT:
X	       value_int(ret) = (int)value_float(val);
X	       break;
X
X	  case STRING:
X	       value_int(ret) = atonum(aw, value_string(val), 0);
X	       break;
X
X	  default:
X	       value_int(ret) = (int)value_any(val);
X	       break;
X	  }
X	  break;
X
X     case FLOAT:
X	  switch(value_type(val)) {
X	  case CHAR:
X	       value_float(ret) = (FTYPE)value_char(val);
X	       break;
X
X	  case INT:
X	       value_float(ret) = (FTYPE)value_int(val);
X	       break;
X
X	  case STRING:
X	       value_float(ret) = (FTYPE)atonum(aw, value_string(val), 0);
X	       break;
X
X	  default:
X	       value_any(ret) = value_any(val);
X	       break;
X	  }
X	  break;
X
X     case STRING:
X	  switch(value_type(val)) {
X	       String str;
X
X	  case CHAR:
X	       str = XtMalloc(2);
X	       str[0] = value_char(val);
X	       str[1] = '\0';
X	       value_aobj(ret) = new_aobj(str);
X	       break;
X
X	  case INT:
X	       str = numtoa(aw, value_int(val), 0);
X	       value_aobj(ret) = new_aobj(XtNewString(str));
X	       break;
X
X	  case FLOAT:
X	       str = ftoa(value_float(val));
X	       value_aobj(ret) = new_aobj(XtNewString(str));
X	       break;
X
X	  case LIST:
X	       value_aobj(ret) = new_aobj(list_to_string(aw, value_list(val)));
X	       break;
X
X	  case WCLASS:
X	       if ((str = map_wclass_to_wname(value_wclass(val))) != NULL)
X		    value_aobj(ret) = new_aobj(XtNewString(str));
X	       else
X		    value_clear(ret);
X	       break;
X
X	  default:
X	       value_class(ret) = STATIC;
X	       value_aobj(ret) = new_aobj(value_any(val));
X	       break;
X	  }
X	  break;
X
X     case LIST:
X	  switch(value_type(val)) {
X
X	  case CHAR:
X	       value_aobj(ret) = new_aobj(list_from_string(aw, numtoa(aw,
X							     value_char(val),
X							     0)));
X	       break;
X
X	  case INT:
X	       value_aobj(ret) = new_aobj(list_from_string(aw, numtoa(aw,
X							     value_int(val),
X							     0)));
X	       break;
X
X	  case FLOAT:
X	       value_aobj(ret) =
X		    new_aobj(list_from_string(aw, ftoa(value_float(val))));
X	       break;
X
X	  case STRING:
X	       value_aobj(ret) = 
X		    new_aobj(list_from_string(aw, value_string(val)));
X	       break;
X
X	  default:
X	       value_class(ret) = STATIC;
X	       value_aobj(ret) = new_aobj(value_any(val));
X	       break;
X	  }
X	  break;
X
X     case WCLASS:
X	  if (value_type(val) != STRING) {
X	       exec_warn("cast: Attempt to coerce type '%s' to WidgetClass",
X			 type_name(value_type(val)));
X	       value_clear(ret);
X	  }
X	  else
X	       value_wclass(ret) = map_wname_to_wclass(value_string(val));
X	  break;
X
X     default:
X	  value_any(ret) = value_any(val);
X	  break;
X     }
X     return(ret);
X}
END_OF_FILE
if test 16995 -ne `wc -c <'convert.c'`; then
    echo shar: \"'convert.c'\" unpacked with wrong size!
fi
# end of 'convert.c'
fi
if test -f 'etc/strsed.3c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'etc/strsed.3c'\"
else
echo shar: Extracting \"'etc/strsed.3c'\" \(14113 characters\)
sed "s/^X//" >'etc/strsed.3c' <<'END_OF_FILE'
X.\"
X.\" $Header: /usr/src/local/awl/etc/RCS/strsed.3c,v 1.1 90/04/19 20:13:24 jkh Exp $
X.\"
X.\"
X.\" $Log:	strsed.3c,v $
Revision 1.1  90/04/19  20:13:24  jkh
Initial revision
X
X.\" Revision 1.6  90/04/19  18:34:27  terry
X.\" comp.sources.unix 2nd release.
X.\" 
X.\" Revision 1.5  90/04/15  18:09:38  terry
X.\" Fixed silly log messages...
X.\" 
X.\" Revision 1.4  90/04/15  18:05:06  terry
X.\" Mentioned Spencer versus GNU differences. Added new example.
X.\"
X.\" Revision 1.3  90/03/07  15:48:59  terry
X.\" Lots of little things. 
X.\" 
X.\" Revision 1.2  90/03/06  22:48:00  terry
X.\" Changed the bit about the 3rd arg - which is now necessary.
X.\" 
X.\" Revision 1.1  90/01/18  20:03:54  terry
X.\" Initial revision
X.\" 
X.\"
X.TH STRSED 3C
X.SH NAME
strsed \- ed(1)/tr(1)\-like substitute and replace function.
X.SH SYNOPSIS
X\fBchar *strsed(string, command, 0)
X.br
char *string;
X.br
char *command;\fR
X.br
X.sp
or
X.sp
X\fBchar *strsed(string, command, range)
X.br
char *string;
X.br
char *command;
X.br
int range[2];\fR
X.SH DESCRIPTION
X.B Strsed 
is a regular expression pattern match and replace
function that also combines 
X.BR tr (1)\-like
transliteration. A regular expression package is used 
for the regular expression matching. Currently this must be
either the GNU Emacs regex package or Henry Spencer's package.
X.PP
X.B Strsed
can be used to provide the
functionality of most of the other more "complicated"
string functions (e.g. 
X.BR strchr ,
X.BR strrchr ,
X.BR strpbrk ,
X.BR strspn ,
X.BR strcspn ,
and
X.BR strtok ),
although less efficiently
in each case, due to its generality.
X.B Strsed
is a very powerful and general function that can be used
to carry out complicated string manipulations such as 
those that are possible in text editors.
X.SH USAGE
X.I String
should be a null\-terminated character string.
A copy is made and will be operated on according to the 
search and replace instructions contained in 
X.IR command .
Unless an error occurs (see ERRORS), the passed character strings
X.I string 
and
X.I command
are 
X.I never
corrupted, and the string that is returned may always 
be passed to 
X.B free()
since its space is obtained from 
X.BR malloc() .
X.PP
Both 
X.I string
and 
X.I command
may contain the following C\-like escape sequences:
X.sp
X    \eb      Backspace.
X.br
X    \ef      Formfeed.
X.br
X    \en      Newline.
X.br
X    \er      Carriage Return.
X.br
X    \es      Space.
X.br
X    \et      Horizontal Tab.
X.br
X    \ev      Vertical Tab.
X.br
X    \ez      Used to remove ambiguity if necessary.
X.br
X    \e0\-9    A reference to a register.
X.br
X             (except for \e0 in a regular expression.)
X.br
X    \e0x3d   The character whose value is 3d hexadecimal.
X.br
X    \e0X3d   The character whose value is 3d hexadecimal.
X.br
X    \e040    The character whose value is 40 octal.
X.br
X    \e32     The character whose value is 32 decimal.
X.sp
The NUL (0) character cannot be specified. 
A '\e' followed by one to three digits can be interpreted in
several ways. If one or two hex digits are preceeded by 
an 'x' or an 'X',
they will be taken as specifying a character in hexadecimal.
If there are exactly three
octal digits and the first is in the range '0' to '3'
then they are taken as specifying a character in octal. 
Otherwise a single digit
is taken to be a register reference and two or three digits
are interpreted as specifying a character in decimal.
X\ez can be used to 
avoid problems with ambiguity. For instance,
X.B \e007
will be interpreted by
X.B strsed
as octal 007. To specify the contents of register zero (\e0) 
followed by the two characters "07", use 
X.BR \e0\ez07 .
The \ez makes it clear what is meant (acting like a punctuation mark)
and is otherwise ignored.
X.PP
X.B Strsed 
allows 
X.BR ed (1)\-like
regular expressions and substitutions
on 
X.IR string .
The search and replace command is specified by
X.IR command .
The format of
X.I command
should be one of
X.sp
X\fBs/search_pattern/replacement/\fR
X.br
X\fBg/search_pattern/replacement/\fR
X.br
X\fB/search_pattern/\fR
X.PP
In the first form, the search and replace is performed once on
the string, whilst in the second, the replacement is done globally
X(i.e. for every occurrence of the search pattern in 
X.IR string .).
If 
X.I replacement
is empty, then the matched text will
be replaced by nothing \- i.e. deleted.
The third form requests searching only (see SEARCHING ONLY).
X.PP
The delimiter character separating the various parts
of the
X.I command
does not have to be a '/', and may be any simple character
X(other than '\e'). If the delimiter character is meant to appear
literally in any part of the command, escape it with a '\e'.
X.PP
X.I Search_pattern
is a full regular expression
X(see 
X.BR ed (1)), 
including register
specifications (i.e. \fB\e( ... \e)\fR) and register references, 
X(e.g. \fB\e2\fR)
but not the \fB{m,n}\fR 
repetition feature of 
X.BR ed (1).
X.PP
X.I Replacement
consists of ordinary characters and/or register references 
X(e.g. \fB\e1\fR or \fB\e2\fR.) \fB\e0\fR means the entire matched 
text. In addition, a
register reference may be immediately followed by a 
transliteration request, of the form 
X.br
X\fB{char\-list\-1}{char\-list\-2}\fR.
X.br
The characters from 
X.I char\-list\-1
will be transliterated into the corresponding ones from 
X.I char\-list\-2 
in the same manner as
X.BR tr (1). 
If the register reference before a transliteration 
request is omitted, it defaults to \fB\e0\fR.
Within a transliteration request, the characters
X"}" and "\-" are metacharacters and must be escaped with
a leading \e if you want them to be interpreted literally.
Character ranges such as a\-z are expanded in the same
fashion as 
X.BR tr (1).
If 
X.I char\-list\-2
is shorter than 
X.I char\-list\-1
then 
X.I char\-list\-2
is padded to be the same length as
X.I char\-list\-1
by repeating its last character as many times as are needed.
XFor example, the transliteration request
X.br
X.B {a\-z}{X}
X.br
will transliterate all lower case letters into an 'X'.
Character ranges may be increasing or decreasing.
X.PP
Unusual character ranges (such as 
X.BR a\-f\-0\-\e0x2d\-c )
are interpreted as running from their first character
to their last (so the above would be treated as 
X.BR a\-c ).
Note that it is
X.B not
possible (in this release) to specify the complement of a 
character range in a transliteration request. However, this 
can be done in the
X.I search_pattern
by commencing a character class with a "^" in the normal
regular expression fashion.
X.PP
The highest register that can be referenced is \fB\e9\fR.
X.SH EXAMPLES
Here are some example
X.I command
strings that might be given to 
X.BR strsed .
X.sp
X\fB/a/A/\fR                    # Change the first 'a' into an 'A'
X.br
X\fBg/a/A/\fR                   # Change every 'a' into an 'A'
X.br
X\fBg/://\fR                     # Delete every ':'
X.br
X\fBg/jack/jill/\fR             # Change every 'jack' to a 'jill'
X.br
X\fB/[^\es\et]/X/\fR              # Change the first non\-whitespace character into an 'X'.
X.SH "ADVANCED EXAMPLES"
In what follows, \fB\e(\fR represents the
start of a register capture, and \fB\e)\fR the end. This corresponds
to the normal GNU regex set up. With Henry
Spencer's package, \fB(\fR and \fB)\fR are metacharacters and so
the \fB\e\fR would be omitted.
X.sp
X\fB/\e([\es\et]*\e)\e([^\es\et]*\e)/\e1\e2{a\-z}{A\-Z}/\fR
X.sp
This converts the first non\-whitespace word to upper case,
preserving any initial whitespace.
It catches the first run of spaces and TABs into register
one \e([\es\et]*\e), and then the following run of non\-white
characters into register two \e([^\es\et]*\e). The replacement,
X\e1\e2{a\-z}{A\-Z} specifies register 1 (the whitespace) followed
by the contents of register 2 transliterated into uppercase.
This would produce 
X.br
X"   SPOTTED pinto bean" 
X.br
if called on the string 
X.br
X"   spotted pinto bean".
X.sp
X\fBg/\e([a\-z]\e)\e1+/\e1/\fR
X.sp
This performs the same function
as tr \-s. That is, it squeezes runs of identical characters
X(in the range a to z) down to a single instance of that 
character. So "beeee good" becomes "be god". The "+" is the
regular expression notation meaning "one or more".
X(Note: this works with the GNU regex package but not with Henry Spencer's.)
X.sp
X\fBg/\e([\et\es]*\e)\e(.\e)\e([^\et\es]*\e)/\e1\e2{a\-z}{A\-Z}\e3/\fR
X.sp
This example capitalises the first letter of each word in the string,
and preserves all whitespace. It catches three things,
X.br
X1) the initial whitespace         \e([\et\es]*\e)  in register 1
X.br
X2) the next letter                \e(.\e)        in register 2
X.br
X3) the following nonwhite letters \e([^\et\es]*\e) in register 3
X.br
and then prints them out as they were found, with the only
difference being the uppercase conversion of the contents of
register 2. Given the string
X.br
X"  this is a line  " 
X.br
this command would
return 
X.br
X"  This Is A Line  ".
X.br
If the initial 'g' was not present in the command, then the capitalisation
would only be done to the first word in the string. 
It is important to understand this difference well.
X.sp
X\fB/\e(..*\e)\e1/\e1/\fR
X.sp
This matches lines that contain the same text twice, replacing it by
a single copy of the doubled text. Given the string
X.br
X"tsetse"
X.br
this command would return
X.br
X"tse".
X(Note: this works with the GNU regex package but not with Henry Spencer's.)
X.SH SEARCHING ONLY
X.B Strsed 
may be used to search for a regular expression in a
string, but perform no action. The portion of the string
that matched will be returned in the third argument,
X.IR range .
In this case 
X.I command
should be of the form 
X.IR /pattern/ .
On return, 
X.I range[0] 
will contain an index into the original
string to indicate where the match began, and 
X.I range[1] 
will index the first character after the end of the match. For
example, after the call 
X.sp
strsed("two big macs please", "/b.*c/", range);
X.sp
X.I range[0] 
will contain 4 and 
X.I range[1]
will contain 11.
If no match is found, both elements of
X.I range
will contain \-1.
X.SH DIAGNOSTICS
If 
X.B strsed 
detects any error it returns NULL. This can happen if the
syntax of 
X.I command
is incorrect, if the regular expression in 
X.I command
is incorrect, if space cannot be obtained from
X.BR malloc ,
or for other similar reasons. Note that it is 
X.B not
an error if the empty string is returned.
X.PP
In all other cases,
X.B strsed
returns a pointer to a new string whose space has been obtained from 
X.BR malloc .
In the case of substitute and replace, it is possible to determine
whether a substitution was actually done to
X.IR string ,
as the values returned in the
X.I range
array will not be -1 if a match occurred. The 
X.I range 
array will not necessarily indicate the matched portion (think about 
global replacements \- what would the correct range be?), but can be
used to check if a substitution occurred or not.
X.SH "COMPILING AND LINKING STRSED"
X.B Strsed
should be compiled with the \-O and \-c options of your C compiler.
It has no main() function. When you come to link, you use strsed.o 
and the appropriate objects from the regular expression package that you
are using. If this is the GNU package, you need regex.o from the 
X18.55 (or 18.54) Emacs distribution, if Henry Spencer's package,
regexp.o and regerror.o from his package.
X.SH "NOTES ON REGULAR EXPRESSIONS"
Different regular expression packages may have slight differences in what they support.
At present,
X.B strsed
allows either GNU or Henry Spencer's regular expression 
package. The only difference from a
X.B strsed
user's perspective is that with GNU, a regular expression may contain a register
reference, but with Henry Spencer's it may not. Thus 
X.br
X\fB\e([a-z]\e)\e\1\fR
X.br
is only valid for GNU regular expressions. This is the reason why two of the
advanced examples above can only be done when you use the GNU regular expression package.
X.PP
It is possible that the regular expression language that is recognised may differ
slightly from installation to installation and from regular expression package
to regular expression package. Henry Spencer's regular expression package
should have the same syntax everywhere. The 
GNU package is configurable at compile time, and may have different settings
for recognition of meta-characters. So on one machine, the character
X"|" might be taken as being the OR operator, whilst somewhere else
you need to give "\e|" \- or vice-versa. This could be a pain in the
neck, but there's not alot that can be done about it. 
X.PP
If you are using GNU regex and you
X.I really 
need to know the difference in a portable way,
use #defines to act differently at compile time when constructing commands for 
X.BR strsed ,
according to what is set in regex.h.
X.PP
As distributed, the example files for those who wish to use the GNU
package expect it to have been compiled as it was distributed as part
of Emacs. So things should be fine. If you adapt
X.B strsed
to use another regular expression package you will
probably need to modify the example files if you test it with the checking
programs included in this distribution.
X.SH "COPYRIGHT INFORMATION"
You should be aware that if you use the GNU regular expression package in
conjunction with
X.B strsed
then you are subject to the GNU Public License. If you use Henry Spencer's
package then you are subject to his copyright. 
X.B Strsed
is distributed under
the same conditions as Henry Spencer's package, that being the weaker of 
the two restrictions. Please see the sources for details.
X.SH AUTHOR
Terry Jones
X.br
PCS Computer Systeme GmbH
X.br
Pfaelzer\-Wald\-Str 36
X.br
X8000 Muenchen 90
X.br
West Germany       49\-89\-68004288
X.sp
terry@distel.pcs.com  or ...!{pyramid,unido}!pcsbst!distel!terry
X.sp
April 19th, 1990.
X.SH ACKNOWLEDGEMENTS
Many thanks to Jordan K. Hubbard for discussions, bugfinding,
handholding, forcing me to use Emacs and torrents of (usually) uncalled\-for abuse.
To John B. Thiel for lots of help with portability concerns and
suggestions for modifications to use either GNU or Henry Spencer regex packages,
to Henry Spencer for his routines and answering questions about them, and to
Paul E. Maisano.
X.SH SEE ALSO
X.BR ed (1),
X.BR tr (1).
END_OF_FILE
if test 14113 -ne `wc -c <'etc/strsed.3c'`; then
    echo shar: \"'etc/strsed.3c'\" unpacked with wrong size!
fi
# end of 'etc/strsed.3c'
fi
if test -f 'macros.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'macros.h'\"
else
echo shar: Extracting \"'macros.h'\" \(15211 characters\)
sed "s/^X//" >'macros.h' <<'END_OF_FILE'
X#ifndef _MACROS_H_INCLUDE
X#define _MACROS_H_INCLUDE
X
X/* $Header: /usr/src/local/awl/RCS/macros.h,v 2.4 90/04/19 20:05:22 jkh Exp $ */
X
X/*
X *
X *                   Copyright 1989, 1990
X *                    Jordan K. Hubbard
X *
X *		  PCS Computer Systeme, GmbH.
X *	             Munich, West Germany
X *
X *
X * This file is part of AWL.
X *
X * AWL is free software; you can redistribute it and/or modify
X * it under the terms of the GNU General Public License as published by
X * the Free Software Foundation; either version 1, or (at your option)
X * any later version.
X *
X * AWL is distributed in the hope that it will be useful,
X * but WITHOUT ANY WARRANTY; without even the implied warranty of
X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X * GNU General Public License for more details.
X *
X * You should have received a copy of the GNU General Public License
X * along with AWL; see the file COPYING.  If not, write to
X * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
X *
X *
X */
X
X/*
X * Here are all the various and sundry macros that make life easier.
X *
X * $Log:	macros.h,v $
X * Revision 2.4  90/04/19  20:05:22  jkh
X * Alpha checkin.
X * 
X * Revision 2.3  90/03/31  22:17:55  jkh
X * None.
X * 
X * Revision 2.2  90/03/27  08:33:01  jkh
X * Some general cleanup.
X * 
X * Revision 2.1  90/03/27  08:00:26  jkh
X * Added evil XtColormap macro. See comment.
X * 
X * Revision 2.0  90/03/26  01:43:26  jkh
X * pre-beta check-in
X * 
X */
X
X/* General utility macros */
X
X#define Local static
X#define Import extern
X#define Export
X
X#if defined(_GNUC_) && !defined(NOINLINE)
X#define Inline inline
X#else
X#define Inline
X#endif
X
X#ifndef TRUE	/* someday these will be someplace reliable (posix?) */
X#define TRUE	(1)
X#define FALSE	(0)
X#endif
X
X/* What version are we? */
X#define VERSION		0
X
X#define UNDEF_ADDR	-1
X
X/* For signals */
X#define MY_SIG_DFL	0
X#define MY_SIG_IGN	1
X
X/* define the size of global and "alist" hash tables */
X#define GLOBAL_HASH_SIZE	97
X#define ALIST_HASH_SIZE		37
X
X/* For backslash_eliminate. This has to stay in sync with strsed.c. Puke. */
X#define NORMAL_ELIMINATE	2
X
X/* number of saved registers in stack frame */
X#define FRAME_REG_SIZE	3
X
X/* how to get to a given argument via the frame pointer */
X#define FRAME_OFFSET(parm) \
X     ((parm) < 0 ? (awl_fp(aw) - (awl_nparms(aw) + (parm) + FRAME_REG_SIZE)) \
X      : (awl_fp(aw) + (parm)))
X
X/* FILEPXDESC macros */
X#define PX_IN		0
X#define PX_OUT		1
X
X#ifndef NFILES		/* this is usually hard to find */
X#define NFILES		64
X#endif
X
X#ifndef MAXSIG
X#define MAXSIG		32
X#endif
X
X/*
X * All these are power-of-2 - 8 so that malloc() doesn't allocate
X * two blocks instead of one (as it would if the amount was already
X * at the edge of a boundry). In practice, this doesn't usually happen
X * with values < 1K, but some malloc routines allocate block lists for
X * the smaller requests too.
X */
X#define TEXT_INCR	1016	/* text segment increment size */
X#define LTAB_INCR	248	/* line table increment size */
X#define STACK_INCR	56	/* initial stack segment size */
X#define ALLOC_INCR	56	/* allocation tick */
X
X/* For mapping widget/resource names in gperf files */
X#define DEFRMAP(name) \
X     Local void name(aw, args, idx, res) \
X     AwlWidget aw; Arg *args; int *idx; Resource res;
X
X#define DEFWMAP(name) \
X     Local void name(n, class, parent, args, nargs) \
X     String n; WidgetClass class; Widget parent; Arg *args; int nargs;
X
X#define MAP(name) ((WidgetClass *)(name))
X
X
X#if defined(__STDC__) && !defined(UNIXCPP)	/* ANSI */
X#define DEFUN(name)	Export Value awl_##name(aw) \
X			AwlWidget aw;
X
X#define F_DECLARE(awl_widget, name, args) \
X     { \
X     extern Value awl_##name(); \
X     addr_fp(addr) = awl_##name; \
X     symbol_def_function(awl_widget, #name, FUNC_BUILTIN, args, addr, FALSE); \
X     }
X
X#define C_DECLARE(awl_widget, name, type, val) \
X     symbol_def_constant(awl_widget, #name, type, val)
X
X#define V_DECLARE(awl_widget, name, type, val) \
X     symbol_def_variable(awl_widget, #name, type, val)
X
X#else
X#define DEFUN(name)	Export Value awl_/**/name(aw) \
X     			AwlWidget aw;
X
X#define F_DECLARE(awl_widget, name, args) \
X     { \
X     extern Value awl_/**/name(); \
X     addr_fp(addr) = awl_/**/name; \
X     symbol_def_function(awl_widget, "name", FUNC_BUILTIN, args, addr, FALSE);\
X     }
X
X#define C_DECLARE(awl_widget, name, type, val) \
X     symbol_def_constant(awl_widget, "name", type, val)
X
X#define V_DECLARE(awl_widget, name, type, val) \
X     symbol_def_variable(awl_widget, "name", type, val)
X
X#endif
X
X/* Define this as the type of float you want to use */
X#define FTYPE		float
X
X#ifndef MAXFLOAT
X#define MAXFLOAT ((float)3.40282346638528860e+38)
X#endif
X
X/* For the POP operator */
X#define DISCARD		0
X#define NODUP		1
X#define DUPVAL		2
X#define DUPTARG		3
X
X/*
X * Now we get to all sorts of "accessor" macros. Yeah, I'm on a Common Lisp
X * kick, but that's beside the point. None of AWL's internal data types are
X * ever accessed directly; everything going through these macros in order
X * to make radical changes in awl's internal structure a lot easier.
X * This approach has already saved my bacon about 3 times!
X *
X * (P.S. If you think these macros are hairy, hah. Look at a Common Lisp
X * loop macro sometime).
X */
X
X/* Process accessors */
X#define process_size		(sizeof(struct _process))
X#define proc_pid(proc)		(((Process)(proc))->pid)
X#define proc_in(proc)		(((Process)(proc))->in)
X#define proc_out(proc)		(((Process)(proc))->out)
X
X/* Allocated object accessors */
X#define aobj_size		(sizeof(struct _allocobj))
X#define aobj_cnt(ao)		(((AllocObj)(ao))->cnt)
X#define aobj_ptr(ao)		(((AllocObj)(ao))->ptr)
X#define aobj_string(ao)		((String)aobj_ptr(ao))
X#define aobj_list(ao)		((String *)aobj_ptr(ao))
X
X/* Address accessors */
X#define addr_size		(sizeof(struct _addr))
X#define addr_fp(adr)		((adr).s)
X#define addr_ep(adr)		((adr).f)
X#define addr_pc(adr)		((adr).u)
X
X/* Datum accessors */
X#define datum_size		(sizeof(struct _datum))
X#define datum_any(dat)		((dat).a)
X#define datum_aobj(dat)		((dat).o)
X#define datum_char(dat)		((dat).b)
X#define datum_file(dat)		((dat).z)
X#define datum_float(dat)	((dat).f)
X#define datum_int(dat)		((dat).i)
X#define datum_range(dat)	((dat).r)
X#define datum_symbol(dat)	((dat).y)
X#define datum_wclass(dat)	((dat).c)
X#define datum_widget(dat)	((dat).w)
X#define datum_list(dat)		(aobj_list(datum_aobj(dat)))
X#define datum_string(dat)	(aobj_string(datum_aobj(dat)))
X
X/* Range value accessors */
X#define range_min(rng)		((rng)[0])
X#define range_max(rng)		((rng)[1])
X
X/* Value accessors */
X#define value_size		(sizeof(struct _val))
X#define value_addr(val)		(&(val))
X#define value_class(val)	((val).class)
X#define value_data(val)		((val).v)
X#define value_type(val)		((val).type)
X#define value_any(val)		(datum_any(value_data(val)))
X#define value_aobj(val)		(datum_aobj(value_data(val)))
X#define value_char(val)		(datum_char(value_data(val)))
X#define value_file(val)		(datum_file(value_data(val)))
X#define value_float(val)	(datum_float(value_data(val)))
X#define value_function(val)	((Function)value_any(val))
X#define value_int(val)		(datum_int(value_data(val)))
X#define value_list(val)		(datum_list(value_data(val)))
X#define value_range(val)	(datum_range(value_data(val)))
X#define value_string(val)	(datum_string(value_data(val)))
X#define value_symbol(val)	(datum_symbol(value_data(val)))
X#define value_wclass(val)	(datum_wclass(value_data(val)))
X#define value_widget(val)	(datum_widget(value_data(val)))
X
X#if defined(__STDC__) && !defined(UNIXCPP)	/* ANSI */
X#define value_set(val, class, type, member, vv) \
X     ((void)(value_class(val) = (class), value_type(val) = (type), \
X     value_##member(val) = (vv)))
X#else
X#define value_set(val, class, type, member, vv) \
X     ((void)(value_class(val) = (class), value_type(val) = (type), \
X     value_/**/member(val) = (vv)))
X#endif
X
X#define value_clear(arg)	value_set((arg), DATA, INT, int, 0)
X
X/* Symbol accessors */
X#define symbol_size		(sizeof(struct _sym))
X#define symbol_root(sym)	(((Symbol)(sym))->aw)
X#define symbol_name(sym)	(((Symbol)(sym))->name)
X#define symbol_alist(sym)	(((Symbol)(sym))->alist)
X#define symbol_parent(sym)	(((Symbol)(sym))->parent)
X#define symbol_value(sym)	(((Symbol)(sym))->v)
X#define symbol_next(sym)	(((Symbol)(sym))->next)
X
X#define symbol_addr(sym)	(value_addr(symbol_value(sym)))
X#define symbol_any(sym)		(value_any(symbol_value(sym)))
X#define symbol_aobj(sym)	(value_aobj(symbol_value(sym)))
X#define symbol_char(sym)	(value_char(symbol_value(sym)))
X#define symbol_class(sym)	(value_class(symbol_value(sym)))
X#define symbol_data(sym)	(value_data(symbol_value(sym)))
X#define symbol_file(sym)	(value_file(symbol_value(sym)))
X#define symbol_float(sym)	(value_float(symbol_value(sym)))
X#define symbol_function(sym)	(value_function(symbol_value(sym)))
X#define symbol_int(sym)		(value_int(symbol_value(sym)))
X#define symbol_list(sym)	(value_list(symbol_value(sym)))
X#define symbol_range(sym)	(value_range(symbol_value(sym)))
X#define symbol_string(sym)	(value_string(symbol_value(sym)))
X#define symbol_symbol(sym)	(value_symbol(symbol_value(sym)))
X#define symbol_type(sym)	(value_type(symbol_value(sym)))
X#define symbol_wclass(sym)	(value_wclass(symbol_value(sym)))
X#define symbol_widget(sym)	(value_widget(symbol_value(sym)))
X
X#define is_allocated_type(typ)	((typ) == STRING || (typ) == LIST)
X
X#define is_filedesc_type(typ)	((typ) == FILEDESC || (typ) == FILEPDESC)
X
X#define is_function_type(typ)	((typ)==FUNC_EXTERN || (typ)==FUNC_ACTION || \
X				 (typ)==FUNC_CALLBACK || (typ)==FUNC_USER || \
X				 (typ)==FUNC_BUILTIN)
X
X#define is_precious(class)	((class) == CONSTANT || (class) == ALLOCATED)
X
X#define is_register(typ)	((typ) == _PC || (typ) == _SP || (typ) == _FP)
X
X#define AOBJCASE		case STRING: case LIST
X
X#define symbol_is_char(sym)	(symbol_type(sym) == CHAR)
X#define symbol_is_float(sym)	(symbol_type(sym) == FLOAT)
X#define symbol_is_int(sym)	(symbol_type(sym) == INT)
X#define symbol_is_list(sym)	(symbol_type(sym) == LIST)
X#define symbol_is_string(sym)	(symbol_type(sym) == STRING)
X#define symbol_is_allocated(sym)(symbol_class(sym) == ALLOCATED)
X#define symbol_is_constant(sym)	(symbol_class(sym) == CONSTANT)
X#define symbol_is_function(sym)	(symbol_class(sym) == FUNCTION)
X#define symbol_is_label(sym)	(symbol_class(sym) == LABEL)
X#define symbol_is_static(sym)	(symbol_class(sym) == STATIC)
X#define symbol_is_precious(sym)	(is_precious(symbol_class(sym)))
X#define symbol_is_register(sym)	(is_register(symbol_type(sym)))
X
X/* Function accessors */
X#define function_size		(sizeof(struct _function))
X#define function_addr(func)	(((Function)(func))->addr)
X#define function_uaddr(func)	(addr_pc(function_addr(func)))
X#define function_faddr(func)	(addr_fp(function_addr(func)))
X#define function_eaddr(func)	(addr_ep(function_addr(func)))
X#define function_nparms(func)	(((Function)(func))->nparms)
X#define function_nlocals(func)	(((Function)(func))->nlocals)
X#define function_data(func)	(((Function)(func))->calldata)
X#define function_end(func)	(((Function)(func))->end)
X
X/* Widget layout accessors */
X#define wl_size			(sizeof(struct _layout))
X#define wl_id(wl)		(((Layout)(wl))->w_id)
X#define wl_name(wl)		(((Layout)(wl))->name)
X#define wl_wclass(wl)		(((Layout)(wl))->class)
X#define wl_parent(wl)		(((Layout)(wl))->parent)
X#define wl_head(wl)		(((Layout)(wl))->head)
X#define wl_tail(wl)		(((Layout)(wl))->tail)
X#define wl_prev(wl)		(((Layout)(wl))->prev)
X#define wl_next(wl)		(((Layout)(wl))->next)
X#define wl_resources(wl)	(((Layout)(wl))->res)
X
X/* Resource accessors */
X#define res_size		(sizeof(struct _resource))
X#define res_name(res)		(((Resource)(res))->name)
X#define res_value(res)		(((Resource)(res))->val)
X#define res_next(res)		(((Resource)(res))->next)
X#define res_parent(res)		(((Resource)(res))->parent)
X
X/* Line table accessors */
X#define ltab_size		(sizeof(struct _ltabent))
X#define ltab_file(ltab)		((ltab).file)
X#define ltab_line(ltab)		((ltab).line)
X#define ltab_start(ltab)	((ltab).start)
X#define ltab_last(ltab)		((ltab).last)
X
X/* Breakpoint accessors */
X#define bkpt_size		(sizeof(struct _breakpoint))
X#define bkpt_next(bk)		(((Breakpoint)(bk))->next)
X#define bkpt_func(bk)		(((Breakpoint)(bk))->func)
X#define bkpt_addr(bk)		(((Breakpoint)(bk))->addr)
X#define bkpt_enable(bk)		(((Breakpoint)(bk))->enable)
X
X/* Color table accessors */
X#define ctab_size		(sizeof(struct _ctable))
X#define ctab_colors(ctab)	(((CTable)(ctab))->colors)
X#define ctab_hash(ctab)		(((CTable)(ctab))->htab)
X#define ctab_nchars(ctab)	(((CTable)(ctab))->nch)
X#define ctab_ncolors(ctab)	(((CTable)(ctab))->ncolors)
X
X/* Widget accessors */
X#define awl_active(aw)		(((AwlWidget)(aw))->awl.compile.active)
X#define awl_bkpts(aw)		(((AwlWidget)(aw))->awl.debuginfo.bkpts)
X#define awl_bomb(aw)		(((AwlWidget)(aw))->awl.sysinfo.bomb_out)
X#define awl_cpp_args(aw)	(((AwlWidget)(aw))->awl.res.cpp_args)
X#define awl_cpp_cmd(aw)		(((AwlWidget)(aw))->awl.res.cpp_command)
X#define awl_ctable(aw)		(((AwlWidget)(aw))->awl.sysinfo.ctable)
X#define awl_current(aw)		(((AwlWidget)(aw))->awl.compile.current)
X#define awl_debug(aw)		(((AwlWidget)(aw))->awl.res.debug)
X#define awl_err(aw)		(((AwlWidget)(aw))->awl.io.err)
X#define awl_estack(aw)		(((AwlWidget)(aw))->awl.seginfo.estack)
X#define awl_etext(aw)		(((AwlWidget)(aw))->awl.seginfo.etext)
X#define awl_externlist(aw)	(((AwlWidget)(aw))->awl.res.externlist)
X#define awl_file(aw)		(((AwlWidget)(aw))->awl.res.file)
X#define awl_fp(aw)		(((AwlWidget)(aw))->awl.segptrs.fp)
X#define awl_in(aw)		(((AwlWidget)(aw))->awl.io.in)
X#define awl_lastinsn(aw)	(((AwlWidget)(aw))->awl.compile.lastinsn)
X#define awl_lastpc(aw)		(((AwlWidget)(aw))->awl.compile.lastpc)
X#define awl_lineinfo(aw)	(((AwlWidget)(aw))->awl.res.lineinfo)
X#define awl_ltab(aw)		(((AwlWidget)(aw))->awl.debuginfo.ltab)
X#define awl_ltabcurr(aw)	(((AwlWidget)(aw))->awl.debuginfo.ltabcurr)
X#define awl_ltabsize(aw)	(((AwlWidget)(aw))->awl.debuginfo.ltabsize)
X#define awl_mainargv(aw)	(((AwlWidget)(aw))->awl.res.argv)
X#define awl_nowarn(aw)		(((AwlWidget)(aw))->awl.res.nowarn)
X#define awl_nparms(aw)		(((AwlWidget)(aw))->awl.segptrs.nparms)
X#define awl_oldsp(aw)		(((AwlWidget)(aw))->awl.segptrs.oldsp)
X#define awl_out(aw)		(((AwlWidget)(aw))->awl.io.out)
X#define awl_pc(aw)		(((AwlWidget)(aw))->awl.segptrs.pc)
X#define awl_radix(aw)		(((AwlWidget)(aw))->awl.io.radix)
X#define awl_sep(aw)		(((AwlWidget)(aw))->awl.io.sep)
X#define awl_showasm(aw)		(((AwlWidget)(aw))->awl.res.showasm)
X#define awl_sp(aw)		(((AwlWidget)(aw))->awl.segptrs.sp)
X#define awl_stack(aw)		(((AwlWidget)(aw))->awl.seginfo.stack)
X#define awl_startfunc(aw)	(((AwlWidget)(aw))->awl.res.startfunc)
X#define awl_text(aw)		(((AwlWidget)(aw))->awl.seginfo.text)
X#define awl_top(aw)		(((AwlWidget)(aw))->awl.sysinfo.top)
X#define awl_trace(aw)		(((AwlWidget)(aw))->awl.res.trace)
X#define awl_version(aw)		(((AwlWidget)(aw))->awl.res.version)
X
X/* These are the flag bits for widget maps */
X#define W_NONE			0x0
X#define W_EXTENDED		0x1
X#define W_POPUP			0x2
X#define W_MANAGER		0x4
X#define W_RESPROC		0x8
X#define W_WIDPROC		0x10
X
X/* These are the flag bits for reserved word maps */
X#define T_NONE			0x0
X#define T_KEYWORD		0x1
X#define T_INTERN_TYPE		0x2
X#define T_TYPE			0x4
X#define T_CLASS			0x8
X#define T_ALL			0xFF
X
X#endif /* _MACROS_H_INCLUDE */
END_OF_FILE
if test 15211 -ne `wc -c <'macros.h'`; then
    echo shar: \"'macros.h'\" unpacked with wrong size!
fi
# end of 'macros.h'
fi
echo shar: End of archive 7 \(of 17\).
cp /dev/null ark7isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 17 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.