|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T e
Length: 11373 (0x2c6d)
Types: TextFile
Names: »escapes.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦6429e39db⟧ »EurOpenD3/news/tmnn.7.8.tar.Z«
└─⟦b5a65d78b⟧
└─⟦this⟧ »src/D.news/escapes.c«
/****************************************************************************
NAME
escapes.c -- %-interpolation functions for strings
SYNOPSIS
#include "news.h"
void escapes(src, dst) -- expand C-like \ escapes
char *src, *dst;
void setexphook(hook) -- set expansion hook
bool (*hook)();
void seeheader(hp) -- set current header for %-escapes
hdr_t *hp;
void strexpand(src, dst) -- expand \ and % escapes
char *src, *dst;
void fnexpand(src, dst) -- expand a filename
char *src, *dst;
DESCRIPTION
This module implements functions to expand escape constructs and (if
RNESCAPES is on) rn-style %-escapes. C-style escapes understood include \n, \b,
\t, \r, and \nnn (octal). The ^-prefix for control characters is also
understood. A leading ~/ is expanded to the user's home directory; a leading
~user is expanded to the home directory of the given user.
Rn-like escapes presently supported are %a, %A, %b, %B, %c, %C, %d, %D, %f,
%F, %H, %i, %l, %L, %n, %N, %o, %p, %P, %r, %R, %s, %S, %t, %T, %x, %X, %z, %~,
%., %$, %%, %{, %(, %[, and %`. The behavior of %F differs slightly from rn's
%F.
An %e escape is provided to try for an article author's name.
One additional escape, %V, yields the contents of the Progname variable.
The %#, %b, %B, %I, %k[0-9], %m, %M, %u, %U, %/, and %\[0-9] escapes are
supported separately by tool-specific modules.
Characters EhOqQwWyYZ!@$&*-=+|<>:;"'? are still available for escape
definition, but hO" collide with rn definitions (see BUGS).
ENVIRONMENT
DOTDIR is queried for the %. escape.
NEWSDIR is queried for the %p escape.
BUGS
The %" escape should be supported here but is not yet implemented. The %h
and %O escapes will not be supported.
AUTHOR
Eric S. Raymond
This software is Copyright (C) 1989 by Eric S. Raymond for the sole purpose
of protecting free redistribution; see the LICENSE file for details.
****************************************************************************/
/* LINTLIBRARY */
#include "news.h"
#include "vio.h"
#include "header.h"
#include "active.h"
#include "newsrc.h"
#ifdef RECMDS
#include "regexp.h"
#endif /* RECMDS */
static hdr_t *machdr = &header;
void escapes(cp, tp)
/* process standard C-style escape sequences in a string */
char *cp, *tp;
{
while (*cp)
{
int cval = 0;
if (*cp == '\\' && strchr("0123456789xX", cp[1]))
{
char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
int dcount = 0;
if (*++cp == 'x' || *cp == 'X')
for (++cp; (dp = strchr(hex, *cp)) && (dcount++ < 2); cp++)
cval = (cval * 16) + (dp - hex) / 2;
else if (*cp == '0')
while (strchr("01234567",*cp) != (char*)NULL && (dcount++ < 3))
cval = (cval * 8) + (*cp++ - '0');
else
while ((strchr("0123456789",*cp)!=(char*)NULL)&&(dcount++ < 3))
cval = (cval * 10) + (*cp++ - '0');
}
else if (*cp == '\\') /* C-style character escapes */
{
switch (*++cp)
{
case '\\': cval = '\\'; break;
case 'n': cval = '\n'; break;
case 't': cval = '\t'; break;
case 'b': cval = '\b'; break;
case 'r': cval = '\r'; break;
default: cval = *cp;
}
cp++;
}
#ifdef ASCII
else if (*cp == '^') /* expand control-character syntax */
{
cval = CTRL(*++cp);
cp++;
}
#endif /* ASCII */
else
cval = *cp++;
*tp++ = cval;
}
*tp = '\0';
}
#ifdef RNESCAPES
private bool (*exphook)() = NULLPRED;
void seeheader(hp)
/* set current-header address for macro-expansion purposes */
hdr_t *hp;
{
machdr = hp;
}
void setexphook(ehook)
/* set the current macroexpansion hook */
bool (*ehook)();
{
exphook = ehook;
}
private void strpget(cgetf, cp, term)
/* snarf everything up to an un-escaped term character into a buffer */
int (*cgetf)(); /* function to grab characters with */
char *cp; /* where to put the characters */
char term; /* terminating character */
{
bool literal = FALSE;
int c;
while ((c = (*cgetf)()) != EOF)
if (c != (int)term || literal)
literal = ((*cp++ = c) == '\\');
else
break;
*cp = '\0';
}
private int lexpand(cgetf, cungetf, buf)
/* expand the given %-construct into the given buffer */
int (*cgetf)(); /* function to grab characters with */
int (*cungetf)(); /* function to push characters back with */
char *buf; /* buffer to expand esacapes into */
{
bool qprefix = '\0';
char lprefix[SBUFLEN];
#ifdef RECMDS
struct regexp *re;
#endif /* RECMDS */
char *cp, c = (*cgetf)();
/* snarf up a prefix qualifier, if any */
if (c == '^' || c == '_')
{
qprefix = c;
c = (*cgetf)();
}
/* snarf up a length-limit prefix, if there is one */
lprefix[1] = '\0';
if (isdigit(c) || ((c=='.' || c=='-') && isdigit((*cungetf)((*cgetf)()))))
{
for (cp = lprefix + 1; isdigit(c) || c=='.' || c=='-'; c = (*cgetf)())
*cp++ = c;
*cp = '\0';
}
buf[0] = '\0';
switch(c)
{
case 'a': (void) sprintf(buf, "%d", msgnum()); break;
case 'A': (void) artname(&art, buf); break;
#ifndef NONLOCAL
case 'c': (void) strcpy(buf, artdir(ngname())+strlen(site.textdir)+1); break;
case 'd': (void) strcpy(buf, artdir(ngname())); break;
#endif /* NONLOCAL */
case 'C': (void) strcpy(buf, ngname()); break;
case 'D': (void) strcpy(buf, machdr->h_distribution); break;
case 'e': author(machdr, buf); break;
case 'f':
(void) strcpy(buf,
hlnblank(machdr->h_replyto)
? machdr->h_replyto : machdr->h_from);
break;
case 'F':
(void) strcpy(buf,
hlnblank(machdr->h_followto)
? machdr->h_followto : machdr->h_newsgroups);
break;
case 'H': (void) strcpy(buf, site.pathname); break;
case 'i': (void) strcpy(buf, machdr->h_ident); break;
case 'l': (void) strcpy(buf, site.notify); break;
case 'L': (void) strcpy(buf, username); break;
case 'n': (void) strcpy(buf, machdr->h_newsgroups); break;
case 'N': (void) strcpy(buf, fullname(username)); break;
case 'o': (void) strcpy(buf, organization()); break;
case 'p': (void) strcpy(buf, (cp = getenv("NEWSDIR"))?cp:DEFDIR); break;
#ifndef NONLOCAL
case 'P': (void) strcpy(buf, site.textdir); break;
#endif /* NONLOCAL */
case 'R': (void) sprintf(buf, "%s %s",
machdr->h_references, machdr->h_ident);
break;
case 'r':
if (cp = strrchr(machdr->h_references, '<'))
(void) strcpy(buf, cp);
break;
case 's':
for (cp = machdr->h_subject; !strncmp(cp, "Re: ", 4); cp += 4)
continue;
(void) strcpy(buf, cp);
if (strcmp(buf + strlen(buf) - 7, " - (nf)") == 0)
buf[strlen(buf) - 7] = '\0';
break;
case 'S':
cp = machdr->h_subject;
(void) strcpy(buf, cp + (strcmp(cp, "Re: ") ? 0 : 4));
break;
case 'T':
(void) sprintf(buf, "To: %s\n", machdr->h_path);
if (cp = strchr(buf, '('))
cp[0] = '\0';
(void) strcat(buf, "\n");
break;
case 't':
(void) sprintf(buf, "To: %s",
hlnblank(machdr->h_replyto)
? machdr->h_replyto : machdr->h_from);
if (cp = strchr(buf, '('))
cp[0] = '\0';
(void) strcat(buf, "\n");
break;
case 'V': (void) strcpy(buf, Progname); break;
case 'x': (void) strcpy(buf, site.admdir); break;
case 'X': (void) strcpy(buf, site.libdir); break;
case 'z':
{
(void) artname(&art, bfr);
(void) sprintf(buf, "%ld", filesize(bfr));
}
break;
case '~': (void) strcpy(buf, userhome); break;
case '.': (void) strcpy(buf,
getenv("DOTDIR") ? getenv("DOTDIR") : userhome);
break;
case '$': (void) sprintf(buf, "%d", getpid()); break;
case '%': (void) strcpy(buf, "%"); break;
case '[':
{
char *hd, expbuf[BUFLEN];
strpget(cgetf, expbuf, ']');
if ((hd = hlget(expbuf)) != (char *)NULL)
(void) strcpy(buf, hd);
}
break;
case '(':
{
char *ifpart, *thenpart, *elsepart, expbuf[BUFLEN];
strpget(cgetf, bfr, ')'); /* stash away the construct */
strexpand(bfr, expbuf); /* string-expand it */
/* now parse out the parts */
cp = expbuf;
while (*cp && (*cp != '=' || cp == expbuf || cp[-1] == '\\'))
cp++;
if (*cp)
*cp++ = '\0';
ifpart = cp;
while (*cp && (*cp != '?' || cp == expbuf || cp[-1] == '\\'))
cp++;
if (*cp)
*cp++ = '\0';
thenpart = cp;
while (*cp && (*cp != ':' || cp == expbuf || cp[-1] == '\\'))
cp++;
if (*cp)
*cp++ = '\0';
elsepart = cp;
/* and evaluate it */
#ifdef RECMDS
re = regcomp(expbuf);
if (regexec(re, ifpart))
#else
if (strcmp(expbuf, ifpart) == SUCCEED)
#endif /* RECMDS */
(void) strcpy(buf, thenpart);
else
(void) strcpy(buf, elsepart);
}
break;
case '{':
{
char *defpart, expbuf[BUFLEN];
/* parse out the parts */
strpget(cgetf, expbuf, '}'); /* stash away the construct */
cp = expbuf;
while (*cp && (*cp != '-' || cp == expbuf || cp[-1] == '\\'))
cp++;
if (*cp)
*cp++ = '\0';
defpart = cp;
/* and evaluate it */
if (cp = getenv(expbuf))
(void) strcpy(buf, cp);
else if (defpart[0])
(void) strcpy(buf, cp);
}
break;
case '`':
{
char expbuf[BUFLEN];
/* parse out the parts */
strpget(cgetf, expbuf, '`'); /* stash away the construct */
(void) backquote(expbuf, buf, BUFLEN);
}
break;
default: /* no go, try expanding tool-specific escapes */
(*cungetf)(c);
if (exphook != NULLPRED && !(*exphook)(cgetf, cungetf, buf))
return(0);
}
/* finally, apply the modifiers */
if (qprefix)
if (qprefix == '^')
buf[0] = toupper(buf[0]);
else if (qprefix == '_' && (cp = strchr(buf, '.')) != (char *)NULL)
cp[1] = toupper(cp[1]);
/* interpret the length prefix, if there is one */
if (lprefix[1])
{
char expbuf[BUFLEN];
lprefix[0] = '%';
(void) strcat(lprefix, "s");
(void) sprintf(expbuf, lprefix, buf);
(void) strcpy(buf, expbuf);
}
return(strlen(buf));
}
private char *scp;
private int sgetc()
{
int cc;
if ((cc = *scp++) == '\0')
return(EOF);
else
return(cc);
}
private int sungetc(c)
char c;
{
return(*--scp = c);
}
#endif /* RNESCAPES */
void strexpand(src, dst)
/* escape-expand a string */
char *src, *dst;
{
#ifndef RNESCAPES
(void) strcpy(dst, src);
#else
char cc, *scpsave = scp; /* make function re-entrant */
register char *to = dst;
for (scp = src; *scp; )
if ((cc = *scp++) == RNESCCHR)
to += lexpand(sgetc, sungetc, to);
else
*to++ = cc;
*to = '\0';
scp = scpsave;
#endif /* RNESCAPES */
/* *after* %-expansion so as not to clobber \%s */
escapes(dst, dst);
}
void fnexpand(src, dst)
/* escape-expand a filename */
char *src, *dst;
{
/* expand leading ~/ to user's home directory */
if (src[0] == '~')
{
if (src[1] == '/')
{
(void) strcpy(dst, userhome);
(void) strcat(dst, "/");
src += 2;
}
else
{
struct passwd *pw = getpwnam(src + 1);
if (pw != (struct passwd *)NULL)
{
(void) strcpy(dst, pw->pw_dir);
src += strlen(src);
}
}
dst += strlen(dst);
}
else if (src[0] == '$') /* expand initial environment variable */
{
char *ep, *sp = strchr(src, '/');
if (sp)
*sp = '\0';
if (ep = getenv(src))
(void) strcpy(dst, ep);
if (sp)
*sp = '/';
src += strlen(src);
dst += strlen(dst);
}
strexpand(src, dst);
}
/* escapes.c ends here */