add
This commit is contained in:
parent
49a1496cbb
commit
c42a1d3d61
31 changed files with 4745 additions and 2 deletions
543
src/cmd/htmlroff/t7.c
Normal file
543
src/cmd/htmlroff/t7.c
Normal file
|
|
@ -0,0 +1,543 @@
|
|||
/*
|
||||
* 7. Macros, strings, diversion, and position traps.
|
||||
*
|
||||
* macros can override builtins
|
||||
* builtins can be renamed or removed!
|
||||
*/
|
||||
|
||||
#include "a.h"
|
||||
|
||||
enum
|
||||
{
|
||||
MAXARG = 10,
|
||||
MAXMSTACK = 40
|
||||
};
|
||||
|
||||
/* macro invocation frame */
|
||||
typedef struct Mac Mac;
|
||||
struct Mac
|
||||
{
|
||||
int argc;
|
||||
Rune *argv[MAXARG];
|
||||
};
|
||||
|
||||
Mac mstack[MAXMSTACK];
|
||||
int nmstack;
|
||||
void emitdi(void);
|
||||
void flushdi(void);
|
||||
|
||||
/*
|
||||
* Run a user-defined macro.
|
||||
*/
|
||||
void popmacro(void);
|
||||
int
|
||||
runmacro(int dot, int argc, Rune **argv)
|
||||
{
|
||||
Rune *p;
|
||||
int i;
|
||||
Mac *m;
|
||||
|
||||
if(verbose && isupperrune(argv[0][0])) fprint(2, "run: %S\n", argv[0]);
|
||||
p = getds(argv[0]);
|
||||
if(p == nil){
|
||||
if(verbose)
|
||||
warn("ignoring unknown request %C%S", dot, argv[0]);
|
||||
if(verbose > 1){
|
||||
for(i=0; i<argc; i++)
|
||||
fprint(2, " %S", argv[i]);
|
||||
fprint(2, "\n");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if(nmstack >= nelem(mstack)){
|
||||
fprint(2, "%L: macro stack overflow:");
|
||||
for(i=0; i<nmstack; i++)
|
||||
fprint(2, " %S", mstack[i].argv[0]);
|
||||
fprint(2, "\n");
|
||||
return -1;
|
||||
}
|
||||
m = &mstack[nmstack++];
|
||||
m->argc = argc;
|
||||
for(i=0; i<argc; i++)
|
||||
m->argv[i] = erunestrdup(argv[i]);
|
||||
pushinputstring(p);
|
||||
nr(L(".$"), argc-1);
|
||||
inputnotify(popmacro);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
popmacro(void)
|
||||
{
|
||||
int i;
|
||||
Mac *m;
|
||||
|
||||
if(--nmstack < 0){
|
||||
fprint(2, "%L: macro stack underflow\n");
|
||||
return;
|
||||
}
|
||||
m = &mstack[nmstack];
|
||||
for(i=0; i<m->argc; i++)
|
||||
free(m->argv[i]);
|
||||
if(nmstack > 0)
|
||||
nr(L(".$"), mstack[nmstack-1].argc-1);
|
||||
else
|
||||
nr(L(".$"), 0);
|
||||
}
|
||||
|
||||
void popmacro1(void);
|
||||
jmp_buf runjb[10];
|
||||
int nrunjb;
|
||||
|
||||
void
|
||||
runmacro1(Rune *name)
|
||||
{
|
||||
Rune *argv[2];
|
||||
int obol;
|
||||
|
||||
if(verbose) fprint(2, "outcb %p\n", outcb);
|
||||
obol = bol;
|
||||
argv[0] = name;
|
||||
argv[1] = nil;
|
||||
bol = 1;
|
||||
if(runmacro('.', 1, argv) >= 0){
|
||||
inputnotify(popmacro1);
|
||||
if(!setjmp(runjb[nrunjb++]))
|
||||
runinput();
|
||||
else
|
||||
if(verbose) fprint(2, "finished %S\n", name);
|
||||
}
|
||||
bol = obol;
|
||||
}
|
||||
|
||||
void
|
||||
popmacro1(void)
|
||||
{
|
||||
popmacro();
|
||||
if(nrunjb >= 0)
|
||||
longjmp(runjb[--nrunjb], 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* macro arguments
|
||||
*
|
||||
* "" means " inside " "
|
||||
* "" empty string
|
||||
* \newline can be done
|
||||
* argument separator is space (not tab)
|
||||
* number register .$ = number of arguments
|
||||
* no arguments outside macros or in strings
|
||||
*
|
||||
* arguments copied in copy mode
|
||||
*/
|
||||
|
||||
/*
|
||||
* diversions
|
||||
*
|
||||
* processed output diverted
|
||||
* dn dl registers vertical and horizontal size of last diversion
|
||||
* .z - current diversion name
|
||||
*/
|
||||
|
||||
/*
|
||||
* traps
|
||||
*
|
||||
* skip most
|
||||
* .t register - distance to next trap
|
||||
*/
|
||||
static Rune *trap0;
|
||||
|
||||
void
|
||||
outtrap(void)
|
||||
{
|
||||
Rune *t;
|
||||
|
||||
if(outcb)
|
||||
return;
|
||||
if(trap0){
|
||||
if(verbose) fprint(2, "trap: %S\n", trap0);
|
||||
t = trap0;
|
||||
trap0 = nil;
|
||||
runmacro1(t);
|
||||
free(t);
|
||||
}
|
||||
}
|
||||
|
||||
/* .wh - install trap */
|
||||
void
|
||||
r_wh(int argc, Rune **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(argc < 2)
|
||||
return;
|
||||
|
||||
i = eval(argv[1]);
|
||||
if(argc == 2){
|
||||
if(i == 0){
|
||||
free(trap0);
|
||||
trap0 = nil;
|
||||
}else
|
||||
if(verbose)
|
||||
warn("not removing trap at %d", i);
|
||||
}
|
||||
if(argc > 2){
|
||||
if(i == 0){
|
||||
free(trap0);
|
||||
trap0 = erunestrdup(argv[2]);
|
||||
}else
|
||||
if(verbose)
|
||||
warn("not installing %S trap at %d", argv[2], i);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
r_ch(int argc, Rune **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(argc == 2){
|
||||
if(trap0 && runestrcmp(argv[1], trap0) == 0){
|
||||
free(trap0);
|
||||
trap0 = nil;
|
||||
}else
|
||||
if(verbose)
|
||||
warn("not removing %S trap", argv[1]);
|
||||
return;
|
||||
}
|
||||
if(argc >= 3){
|
||||
i = eval(argv[2]);
|
||||
if(i == 0){
|
||||
free(trap0);
|
||||
trap0 = erunestrdup(argv[1]);
|
||||
}else
|
||||
if(verbose)
|
||||
warn("not moving %S trap to %d", argv[1], i);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
r_dt(int argc, Rune **argv)
|
||||
{
|
||||
USED(argc);
|
||||
USED(argv);
|
||||
warn("ignoring diversion trap");
|
||||
}
|
||||
|
||||
/* define macro - .de, .am, .ig */
|
||||
void
|
||||
r_de(int argc, Rune **argv)
|
||||
{
|
||||
Rune *end, *p;
|
||||
Fmt fmt;
|
||||
int ignore, len;
|
||||
|
||||
delreq(argv[1]);
|
||||
delraw(argv[1]);
|
||||
ignore = runestrcmp(argv[0], L("ig")) == 0;
|
||||
if(!ignore)
|
||||
runefmtstrinit(&fmt);
|
||||
end = L("..");
|
||||
if(argc >= 3)
|
||||
end = argv[2];
|
||||
if(runestrcmp(argv[0], L("am")) == 0 && (p=getds(argv[1])) != nil)
|
||||
fmtrunestrcpy(&fmt, p);
|
||||
len = runestrlen(end);
|
||||
while((p = readline(CopyMode)) != nil){
|
||||
if(runestrncmp(p, end, len) == 0
|
||||
&& (p[len]==' ' || p[len]==0 || p[len]=='\t'
|
||||
|| (p[len]=='\\' && p[len+1]=='}'))){
|
||||
free(p);
|
||||
goto done;
|
||||
}
|
||||
if(!ignore)
|
||||
fmtprint(&fmt, "%S\n", p);
|
||||
free(p);
|
||||
}
|
||||
warn("eof in %C%S %S - looking for %#Q", dot, argv[0], argv[1], end);
|
||||
done:
|
||||
if(ignore)
|
||||
return;
|
||||
p = runefmtstrflush(&fmt);
|
||||
if(p == nil)
|
||||
sysfatal("out of memory");
|
||||
ds(argv[1], p);
|
||||
free(p);
|
||||
}
|
||||
|
||||
/* define string .ds .as */
|
||||
void
|
||||
r_ds(Rune *cmd)
|
||||
{
|
||||
Rune *name, *line, *p;
|
||||
|
||||
name = copyarg();
|
||||
line = readline(CopyMode);
|
||||
if(name == nil || line == nil){
|
||||
free(name);
|
||||
return;
|
||||
}
|
||||
p = line;
|
||||
if(*p == '"')
|
||||
p++;
|
||||
if(cmd[0] == 'd')
|
||||
ds(name, p);
|
||||
else
|
||||
as(name, p);
|
||||
free(name);
|
||||
free(line);
|
||||
}
|
||||
|
||||
/* remove request, macro, or string */
|
||||
void
|
||||
r_rm(int argc, Rune **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
emitdi();
|
||||
for(i=1; i<argc; i++){
|
||||
delreq(argv[i]);
|
||||
delraw(argv[i]);
|
||||
ds(argv[i], nil);
|
||||
}
|
||||
}
|
||||
|
||||
/* .rn - rename request, macro, or string */
|
||||
void
|
||||
r_rn(int argc, Rune **argv)
|
||||
{
|
||||
USED(argc);
|
||||
renreq(argv[1], argv[2]);
|
||||
renraw(argv[1], argv[2]);
|
||||
ds(argv[2], getds(argv[1]));
|
||||
ds(argv[1], nil);
|
||||
}
|
||||
|
||||
/* .di - divert output to macro xx */
|
||||
/* .da - divert, appending to macro */
|
||||
/* page offsetting is not done! */
|
||||
Fmt difmt;
|
||||
int difmtinit;
|
||||
Rune di[20][100];
|
||||
int ndi;
|
||||
|
||||
void
|
||||
emitdi(void)
|
||||
{
|
||||
flushdi();
|
||||
runefmtstrinit(&difmt);
|
||||
difmtinit = 1;
|
||||
fmtrune(&difmt, Uformatted);
|
||||
}
|
||||
|
||||
void
|
||||
flushdi(void)
|
||||
{
|
||||
int n;
|
||||
Rune *p;
|
||||
|
||||
if(ndi == 0 || difmtinit == 0)
|
||||
return;
|
||||
fmtrune(&difmt, Uunformatted);
|
||||
p = runefmtstrflush(&difmt);
|
||||
memset(&difmt, 0, sizeof difmt);
|
||||
difmtinit = 0;
|
||||
if(p == nil)
|
||||
warn("out of memory in diversion %C%S", dot, di[ndi-1]);
|
||||
else{
|
||||
n = runestrlen(p);
|
||||
if(n > 0 && p[n-1] != '\n'){
|
||||
p = runerealloc(p, n+2);
|
||||
p[n] = '\n';
|
||||
p[n+1] = 0;
|
||||
}
|
||||
}
|
||||
as(di[ndi-1], p);
|
||||
free(p);
|
||||
}
|
||||
|
||||
void
|
||||
outdi(Rune r)
|
||||
{
|
||||
if(!difmtinit) abort();
|
||||
if(r == Uempty)
|
||||
return;
|
||||
fmtrune(&difmt, r);
|
||||
}
|
||||
|
||||
/* .di, .da */
|
||||
void
|
||||
r_di(int argc, Rune **argv)
|
||||
{
|
||||
br();
|
||||
if(argc > 2)
|
||||
warn("extra arguments to %C%S", dot, argv[0]);
|
||||
if(argc == 1){
|
||||
/* end diversion */
|
||||
if(ndi <= 0){
|
||||
// warn("unmatched %C%S", dot, argv[0]);
|
||||
return;
|
||||
}
|
||||
flushdi();
|
||||
if(--ndi == 0){
|
||||
_nr(L(".z"), nil);
|
||||
outcb = nil;
|
||||
}else{
|
||||
_nr(L(".z"), di[ndi-1]);
|
||||
runefmtstrinit(&difmt);
|
||||
fmtrune(&difmt, Uformatted);
|
||||
difmtinit = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* start diversion */
|
||||
/* various register state should be saved, but it's all useless to us */
|
||||
flushdi();
|
||||
if(ndi >= nelem(di))
|
||||
sysfatal("%Cdi overflow", dot);
|
||||
if(argv[0][1] == 'i')
|
||||
ds(argv[1], nil);
|
||||
_nr(L(".z"), argv[1]);
|
||||
runestrcpy(di[ndi++], argv[1]);
|
||||
runefmtstrinit(&difmt);
|
||||
fmtrune(&difmt, Uformatted);
|
||||
difmtinit = 1;
|
||||
outcb = outdi;
|
||||
}
|
||||
|
||||
/* .wh - install trap */
|
||||
/* .ch - change trap */
|
||||
/* .dt - install diversion trap */
|
||||
|
||||
/* set input-line count trap */
|
||||
int itrapcount;
|
||||
int itrapwaiting;
|
||||
Rune *itrapname;
|
||||
|
||||
void
|
||||
r_it(int argc, Rune **argv)
|
||||
{
|
||||
if(argc < 3){
|
||||
itrapcount = 0;
|
||||
return;
|
||||
}
|
||||
itrapcount = eval(argv[1]);
|
||||
free(itrapname);
|
||||
itrapname = erunestrdup(argv[2]);
|
||||
}
|
||||
|
||||
void
|
||||
itrap(void)
|
||||
{
|
||||
itrapset();
|
||||
if(itrapwaiting){
|
||||
itrapwaiting = 0;
|
||||
runmacro1(itrapname);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
itrapset(void)
|
||||
{
|
||||
if(itrapcount > 0 && --itrapcount == 0)
|
||||
itrapwaiting = 1;
|
||||
}
|
||||
|
||||
/* .em - invoke macro when all input is over */
|
||||
void
|
||||
r_em(int argc, Rune **argv)
|
||||
{
|
||||
Rune buf[20];
|
||||
|
||||
USED(argc);
|
||||
runesnprint(buf, nelem(buf), ".%S\n", argv[1]);
|
||||
as(L("eof"), buf);
|
||||
}
|
||||
|
||||
int
|
||||
e_star(void)
|
||||
{
|
||||
Rune *p;
|
||||
|
||||
p = getds(getname());
|
||||
if(p)
|
||||
pushinputstring(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
e_t(void)
|
||||
{
|
||||
if(inputmode&CopyMode)
|
||||
return '\t';
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
e_a(void)
|
||||
{
|
||||
if(inputmode&CopyMode)
|
||||
return '\a';
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
e_backslash(void)
|
||||
{
|
||||
if(inputmode&ArgMode)
|
||||
ungetrune('\\');
|
||||
return backslash;
|
||||
}
|
||||
|
||||
int
|
||||
e_dot(void)
|
||||
{
|
||||
return '.';
|
||||
}
|
||||
|
||||
int
|
||||
e_dollar(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = getnext();
|
||||
if(c < '1' || c > '9'){
|
||||
ungetnext(c);
|
||||
return 0;
|
||||
}
|
||||
c -= '0';
|
||||
if(nmstack <= 0 || mstack[nmstack-1].argc <= c)
|
||||
return 0;
|
||||
pushinputstring(mstack[nmstack-1].argv[c]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
t7init(void)
|
||||
{
|
||||
addreq(L("de"), r_de, -1);
|
||||
addreq(L("am"), r_de, -1);
|
||||
addreq(L("ig"), r_de, -1);
|
||||
addraw(L("ds"), r_ds);
|
||||
addraw(L("as"), r_ds);
|
||||
addreq(L("rm"), r_rm, -1);
|
||||
addreq(L("rn"), r_rn, -1);
|
||||
addreq(L("di"), r_di, -1);
|
||||
addreq(L("da"), r_di, -1);
|
||||
addreq(L("it"), r_it, -1);
|
||||
addreq(L("em"), r_em, 1);
|
||||
addreq(L("wh"), r_wh, -1);
|
||||
addreq(L("ch"), r_ch, -1);
|
||||
addreq(L("dt"), r_dt, -1);
|
||||
|
||||
addesc('$', e_dollar, CopyMode|ArgMode|HtmlMode);
|
||||
addesc('*', e_star, CopyMode|ArgMode|HtmlMode);
|
||||
addesc('t', e_t, CopyMode|ArgMode);
|
||||
addesc('a', e_a, CopyMode|ArgMode);
|
||||
addesc('\\', e_backslash, ArgMode|CopyMode);
|
||||
addesc('.', e_dot, CopyMode|ArgMode);
|
||||
|
||||
ds(L("eof"), L(".sp 0.5i\n"));
|
||||
ds(L(".."), L(""));
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue