shithub: riscv

Download patch

ref: 2c317dccea27212b4a2ba42bd792740ea4bbc689
parent: 260d1eaaa73a377fb7b0cfc00707ddba35a54ccd
parent: 8499401ada316f99d5ea8ef058ca1669468e6a7a
author: cinap_lenrek <[email protected]>
date: Sun Apr 19 20:08:35 EDT 2020

merge

--- a/sys/src/cmd/1a/a.h
+++ b/sys/src/cmd/1a/a.h
@@ -156,7 +156,7 @@
 void	domacro(void);
 void	macund(void);
 void	macdef(void);
-void	macexpand(Sym*, char*);
+void	macexpand(Sym*, char*, int);
 void	macinc(void);
 void	macprag(void);
 void	maclin(void);
--- a/sys/src/cmd/1a/lex.c
+++ b/sys/src/cmd/1a/lex.c
@@ -38,7 +38,7 @@
 		break;
 	} ARGEND
 	if(*argv == 0) {
-		print("usage: %ca [-options] file.s\n", thechar);
+		print("usage: %Ca [-options] file.s\n", thechar);
 		errorexit();
 	}
 	if(argc > 1 && systemtype(Windows)){
@@ -92,10 +92,10 @@
 int
 assemble(char *file)
 {
-	char ofile[100], incfile[20], *p;
+	char *ofile, *p;
 	int i, of;
 
-	strcpy(ofile, file);
+	ofile = strdup(file);
 	p = utfrrune(ofile, pathchar());
 	if(p) {
 		include[0] = ofile;
@@ -103,16 +103,13 @@
 	} else
 		p = ofile;
 	if(outfile == 0) {
-		outfile = p;
-		if(outfile){
+		if(p){
+			outfile = p;
 			p = utfrrune(outfile, '.');
 			if(p)
 				if(p[1] == 's' && p[2] == 0)
 					p[0] = 0;
-			p = utfrune(outfile, 0);
-			p[0] = '.';
-			p[1] = thechar;
-			p[2] = 0;
+			outfile = smprint("%s.%C", outfile, thechar);
 		} else
 			outfile = "/dev/null";
 	}
@@ -120,15 +117,13 @@
 	if(p) {
 		setinclude(p);
 	} else {
-		if(systemtype(Plan9)) {
-			sprint(incfile,"/%s/include", thestring);
-			setinclude(strdup(incfile));
-		}
+		if(systemtype(Plan9))
+			setinclude(smprint("/%s/include", thestring));
 	}
 
 	of = mycreat(outfile, 0664);
 	if(of < 0) {
-		yyerror("%ca: cannot create %s", thechar, outfile);
+		yyerror("%Ca: cannot create %s", thechar, outfile);
 		errorexit();
 	}
 	Binit(&obuf, of, OWRITE);
--- a/sys/src/cmd/1c/bits.c
+++ /dev/null
@@ -1,127 +1,0 @@
-#define	EXTERN
-#include "gc.h"
-
-/*
-Bits
-bor(Bits a, Bits b)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = a.b[i] | b.b[i];
-	return c;
-}
-*/
-
-/*
-Bits
-band(Bits a, Bits b)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = a.b[i] & b.b[i];
-	return c;
-}
-*/
-
-/*
-Bits
-bnot(Bits a)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = ~a.b[i];
-	return c;
-}
-*/
-
-int
-bany(Bits *a)
-{
-	int i;
-
-	for(i=0; i<BITS; i++)
-		if(a->b[i])
-			return 1;
-	return 0;
-}
-
-/*
-int
-beq(Bits a, Bits b)
-{
-	int i;
-
-	for(i=0; i<BITS; i++)
-		if(a.b[i] != b.b[i])
-			return 0;
-	return 1;
-}
-*/
-
-int
-bnum(Bits a)
-{
-	int i;
-	long b;
-
-	for(i=0; i<BITS; i++)
-		if(b = a.b[i])
-			return 32*i + bitno(b);
-	diag(Z, "bad in bnum");
-	return 0;
-}
-
-Bits
-blsh(unsigned n)
-{
-	Bits c;
-
-	c = zbits;
-	c.b[n/32] = 1L << (n%32);
-	return c;
-}
-
-/*
-int
-bset(Bits a, unsigned n)
-{
-	int i;
-
-	if(a.b[n/32] & (1L << (n%32)))
-		return 1;
-	return 0;
-}
-*/
-
-int
-Bconv(va_list *arg, Fconv *fp)
-{
-	char str[STRINGSZ], ss[STRINGSZ], *s;
-	Bits bits;
-	int i;
-
-	str[0] = 0;
-	bits = va_arg(*arg, Bits);
-	while(bany(&bits)) {
-		i = bnum(bits);
-		if(str[0])
-			strcat(str, " ");
-		if(var[i].sym == S) {
-			sprint(ss, "$%ld", var[i].offset);
-			s = ss;
-		} else
-			s = var[i].sym->name;
-		if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
-			break;
-		strcat(str, s);
-		bits.b[i/32] &= ~(1L << (i%32));
-	}
-	strconv(str, fp);
-	return 0;
-}
--- a/sys/src/cmd/2a/a.h
+++ b/sys/src/cmd/2a/a.h
@@ -157,7 +157,7 @@
 void	domacro(void);
 void	macund(void);
 void	macdef(void);
-void	macexpand(Sym*, char*);
+void	macexpand(Sym*, char*, int);
 void	macinc(void);
 void	macprag(void);
 void	maclin(void);
--- a/sys/src/cmd/2a/lex.c
+++ b/sys/src/cmd/2a/lex.c
@@ -38,7 +38,7 @@
 		break;
 	} ARGEND
 	if(*argv == 0) {
-		print("usage: %ca [-options] file.s\n", thechar);
+		print("usage: %Ca [-options] file.s\n", thechar);
 		errorexit();
 	}
 	if(argc > 1 && systemtype(Windows)){
@@ -92,10 +92,10 @@
 int
 assemble(char *file)
 {
-	char ofile[100], incfile[20], *p;
+	char *ofile, *p;
 	int i, of;
 
-	strcpy(ofile, file);
+	ofile = strdup(file);
 	p = utfrrune(ofile, pathchar());
 	if(p) {
 		include[0] = ofile;
@@ -103,16 +103,13 @@
 	} else
 		p = ofile;
 	if(outfile == 0) {
-		outfile = p;
-		if(outfile){
+		if(p){
+			outfile = p;
 			p = utfrrune(outfile, '.');
 			if(p)
 				if(p[1] == 's' && p[2] == 0)
 					p[0] = 0;
-			p = utfrune(outfile, 0);
-			p[0] = '.';
-			p[1] = thechar;
-			p[2] = 0;
+			outfile = smprint("%s.%C", outfile, thechar);
 		} else
 			outfile = "/dev/null";
 	}
@@ -120,15 +117,13 @@
 	if(p) {
 		setinclude(p);
 	} else {
-		if(systemtype(Plan9)) {
-			sprint(incfile,"/%s/include", thestring);
-			setinclude(strdup(incfile));
-		}
+		if(systemtype(Plan9))
+			setinclude(smprint("/%s/include", thestring));
 	}
 
 	of = mycreat(outfile, 0664);
 	if(of < 0) {
-		yyerror("%ca: cannot create %s", thechar, outfile);
+		yyerror("%Ca: cannot create %s", thechar, outfile);
 		errorexit();
 	}
 	Binit(&obuf, of, OWRITE);
--- a/sys/src/cmd/2c/bits.c
+++ /dev/null
@@ -1,127 +1,0 @@
-#define	EXTERN
-#include "gc.h"
-
-/*
-Bits
-bor(Bits a, Bits b)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = a.b[i] | b.b[i];
-	return c;
-}
-*/
-
-/*
-Bits
-band(Bits a, Bits b)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = a.b[i] & b.b[i];
-	return c;
-}
-*/
-
-/*
-Bits
-bnot(Bits a)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = ~a.b[i];
-	return c;
-}
-*/
-
-int
-bany(Bits *a)
-{
-	int i;
-
-	for(i=0; i<BITS; i++)
-		if(a->b[i])
-			return 1;
-	return 0;
-}
-
-/*
-int
-beq(Bits a, Bits b)
-{
-	int i;
-
-	for(i=0; i<BITS; i++)
-		if(a.b[i] != b.b[i])
-			return 0;
-	return 1;
-}
-*/
-
-int
-bnum(Bits a)
-{
-	int i;
-	long b;
-
-	for(i=0; i<BITS; i++)
-		if(b = a.b[i])
-			return 32*i + bitno(b);
-	diag(Z, "bad in bnum");
-	return 0;
-}
-
-Bits
-blsh(unsigned n)
-{
-	Bits c;
-
-	c = zbits;
-	c.b[n/32] = 1L << (n%32);
-	return c;
-}
-
-/*
-int
-bset(Bits a, unsigned n)
-{
-	int i;
-
-	if(a.b[n/32] & (1L << (n%32)))
-		return 1;
-	return 0;
-}
-*/
-
-int
-Bconv(va_list *arg, Fconv *fp)
-{
-	char str[STRINGSZ], ss[STRINGSZ], *s;
-	Bits bits;
-	int i;
-
-	str[0] = 0;
-	bits = va_arg(*arg, Bits);
-	while(bany(&bits)) {
-		i = bnum(bits);
-		if(str[0])
-			strcat(str, " ");
-		if(var[i].sym == S) {
-			sprint(ss, "$%ld", var[i].offset);
-			s = ss;
-		} else
-			s = var[i].sym->name;
-		if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
-			break;
-		strcat(str, s);
-		bits.b[i/32] &= ~(1L << (i%32));
-	}
-	strconv(str, fp);
-	return 0;
-}
--- a/sys/src/cmd/2l/list.c
+++ b/sys/src/cmd/2l/list.c
@@ -52,7 +52,7 @@
 int
 Dconv(Fmt *fp)
 {
-	char str[40], s[20];
+	char str[40];
 	Adr *a;
 	int i, j;
 	long d;
@@ -89,14 +89,11 @@
 
 		if(i != D_NONE) {
 			j = a->scale & 7;
-			snprint(s, sizeof s, "(%R.%c*%c)", i, "WWWWLLLL"[j], "12481248"[j]);
-			strncat(str, s, sizeof str - 1);
-			str[sizeof str - 1] = 0;
+			seprint(strchr(str, 0), &str[sizeof str], "(%R.%c*%c)",
+				i, "WWWWLLLL"[j], "12481248"[j]);
 		}
-		if((i & I_MASK) == I_INDEX3){
-			strncat(str, ")", sizeof str - 1);
-			str[sizeof str - 1] = 0;
-		}
+		if((i & I_MASK) == I_INDEX3)
+			seprint(strchr(str, 0), &str[sizeof str], ")");
 		a->displace = d;
 		a->index = i;
 		goto out;
--- a/sys/src/cmd/5a/a.h
+++ b/sys/src/cmd/5a/a.h
@@ -137,7 +137,7 @@
 void	domacro(void);
 void	macund(void);
 void	macdef(void);
-void	macexpand(Sym*, char*);
+void	macexpand(Sym*, char*, int);
 void	macinc(void);
 void	maclin(void);
 void	macprag(void);
--- a/sys/src/cmd/5a/lex.c
+++ b/sys/src/cmd/5a/lex.c
@@ -42,7 +42,7 @@
 		break;
 	} ARGEND
 	if(*argv == 0) {
-		print("usage: %ca [-options] file.s\n", thechar);
+		print("usage: %Ca [-options] file.s\n", thechar);
 		errorexit();
 	}
 	if(argc > 1 && systemtype(Windows)){
@@ -96,10 +96,10 @@
 int
 assemble(char *file)
 {
-	char ofile[100], incfile[20], *p;
+	char *ofile, *p;
 	int i, of;
 
-	strcpy(ofile, file);
+	ofile = strdup(file);
 	p = utfrrune(ofile, pathchar());
 	if(p) {
 		include[0] = ofile;
@@ -107,16 +107,13 @@
 	} else
 		p = ofile;
 	if(outfile == 0) {
-		outfile = p;
-		if(outfile){
+		if(p){
+			outfile = p;
 			p = utfrrune(outfile, '.');
 			if(p)
 				if(p[1] == 's' && p[2] == 0)
 					p[0] = 0;
-			p = utfrune(outfile, 0);
-			p[0] = '.';
-			p[1] = thechar;
-			p[2] = 0;
+			outfile = smprint("%s.%C", outfile, thechar);
 		} else
 			outfile = "/dev/null";
 	}
@@ -124,15 +121,13 @@
 	if(p) {
 		setinclude(p);
 	} else {
-		if(systemtype(Plan9)) {
-			sprint(incfile,"/%s/include", thestring);
-			setinclude(strdup(incfile));
-		}
+		if(systemtype(Plan9))
+			setinclude(smprint("/%s/include", thestring));
 	}
 
 	of = mycreat(outfile, 0664);
 	if(of < 0) {
-		yyerror("%ca: cannot create %s", thechar, outfile);
+		yyerror("%Ca: cannot create %s", thechar, outfile);
 		errorexit();
 	}
 	Binit(&obuf, of, OWRITE);
--- a/sys/src/cmd/5c/list.c
+++ b/sys/src/cmd/5c/list.c
@@ -42,7 +42,7 @@
 int
 Pconv(Fmt *fp)
 {
-	char str[STRINGSZ], sc[20];
+	char sc[20];
 	Prog *p;
 	int a, s;
 
@@ -59,31 +59,30 @@
 	if(s & C_UBIT)		/* ambiguous with FBIT */
 		strcat(sc, ".U");
 	if(a == AMULL || a == AMULAL || a == AMULLU || a == AMULALU)
-		snprint(str, sizeof str, "	%A%s	%D,R%d,%D", a, sc, &p->from, p->reg, &p->to);
+		return fmtprint(fp, "	%A%s	%D,R%d,%D", a, sc, &p->from, p->reg, &p->to);
 	else
 	if(a == AMOVM) {
 		if(p->from.type == D_CONST)
-			snprint(str, sizeof str, "	%A%s	%R,%D", a, sc, &p->from, &p->to);
+			return fmtprint(fp, "	%A%s	%R,%D", a, sc, &p->from, &p->to);
 		else
 		if(p->to.type == D_CONST)
-			snprint(str, sizeof str, "	%A%s	%D,%R", a, sc, &p->from, &p->to);
+			return fmtprint(fp, "	%A%s	%D,%R", a, sc, &p->from, &p->to);
 		else
-			snprint(str, sizeof str, "	%A%s	%D,%D", a, sc, &p->from, &p->to);
+			return fmtprint(fp, "	%A%s	%D,%D", a, sc, &p->from, &p->to);
 	} else
 	if(a == ADATA)
-		snprint(str, sizeof str, "	%A	%D/%d,%D", a, &p->from, p->reg, &p->to);
+		return fmtprint(fp, "	%A	%D/%d,%D", a, &p->from, p->reg, &p->to);
 	else
 	if(p->as == ATEXT)
-		snprint(str, sizeof str, "	%A	%D,%d,%D", a, &p->from, p->reg, &p->to);
+		return fmtprint(fp, "	%A	%D,%d,%D", a, &p->from, p->reg, &p->to);
 	else
 	if(p->reg == NREG)
-		snprint(str, sizeof str, "	%A%s	%D,%D", a, sc, &p->from, &p->to);
+		return fmtprint(fp, "	%A%s	%D,%D", a, sc, &p->from, &p->to);
 	else
 	if(p->from.type != D_FREG)
-		snprint(str, sizeof str, "	%A%s	%D,R%d,%D", a, sc, &p->from, p->reg, &p->to);
+		return fmtprint(fp, "	%A%s	%D,R%d,%D", a, sc, &p->from, p->reg, &p->to);
 	else
-		snprint(str, sizeof str, "	%A%s	%D,F%d,%D", a, sc, &p->from, p->reg, &p->to);
-	return fmtstrcpy(fp, str);
+		return fmtprint(fp, "	%A%s	%D,F%d,%D", a, sc, &p->from, p->reg, &p->to);
 }
 
 int
@@ -102,7 +101,6 @@
 int
 Dconv(Fmt *fp)
 {
-	char str[STRINGSZ];
 	Adr *a;
 	char *op;
 	int v;
@@ -109,86 +107,77 @@
 
 	a = va_arg(fp->args, Adr*);
 	switch(a->type) {
-
 	default:
-		snprint(str, sizeof str, "GOK-type(%d)", a->type);
-		break;
+		return fmtprint(fp, "GOK-type(%d)", a->type);
 
 	case D_NONE:
-		str[0] = 0;
 		if(a->name != D_NONE || a->reg != NREG || a->sym != S)
-			snprint(str, sizeof str, "%N(R%d)(NONE)", a, a->reg);
-		break;
+			return fmtprint(fp, "%N(R%d)(NONE)", a, a->reg);
+		return 0;
 
 	case D_CONST:
 		if(a->reg != NREG)
-			snprint(str, sizeof str, "$%N(R%d)", a, a->reg);
+			return fmtprint(fp, "$%N(R%d)", a, a->reg);
 		else
-			snprint(str, sizeof str, "$%N", a);
-		break;
+			return fmtprint(fp, "$%N", a);
 
 	case D_SHIFT:
 		v = a->offset;
 		op = "<<>>->@>" + (((v>>5) & 3) << 1);
 		if(v & (1<<4))
-			snprint(str, sizeof str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
+			fmtprint(fp, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
 		else {
 			int sh = (v>>7)&31;
 			if(sh == 0 && (v & (3<<5)) != 0)
 				sh = 32;
-			snprint(str, sizeof str, "R%d%c%c%d", v&15, op[0], op[1], sh);
+			fmtprint(fp, "R%d%c%c%d", v&15, op[0], op[1], sh);
 		}
 		if(a->reg != NREG)
-			snprint(str+strlen(str), sizeof(str)-strlen(str), "(R%d)", a->reg);
-		break;
+			fmtprint(fp, "(R%d)", a->reg);
+		return 0;
 
 	case D_OREG:
 		if(a->reg != NREG)
-			snprint(str, sizeof str, "%N(R%d)", a, a->reg);
+			return fmtprint(fp, "%N(R%d)", a, a->reg);
 		else
-			snprint(str, sizeof str, "%N", a);
-		break;
+			return fmtprint(fp, "%N", a);
 
 	case D_REGREG:
-		snprint(str, sizeof str, "(R%d,R%d)", a->reg, (char)a->offset);
-		break;
+		return fmtprint(fp, "(R%d,R%d)", a->reg, (char)a->offset);
 
 	case D_REG:
-		snprint(str, sizeof str, "R%d", a->reg);
 		if(a->name != D_NONE || a->sym != S)
-			snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
-		break;
+			return fmtprint(fp, "%N(R%d)(REG)", a, a->reg);
+		else
+			return fmtprint(fp, "R%d", a->reg);
 
 	case D_FREG:
-		snprint(str, sizeof str, "F%d", a->reg);
 		if(a->name != D_NONE || a->sym != S)
-			snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
-		break;
+			return fmtprint(fp, "%N(R%d)(REG)", a, a->reg);
+		else
+			return fmtprint(fp, "F%d", a->reg);
 
 	case D_PSR:
-		snprint(str, sizeof str, "PSR");
 		if(a->name != D_NONE || a->sym != S)
-			snprint(str, sizeof str, "%N(PSR)(REG)", a);
-		break;
+			return fmtprint(fp, "%N(PSR)(REG)", a);
+		else
+			return fmtprint(fp, "PSR");
 
 	case D_BRANCH:
-		snprint(str, sizeof str, "%ld(PC)", a->offset-pc);
-		break;
+		return fmtprint(fp, "%ld(PC)", a->offset-pc);
 
 	case D_FCONST:
-		snprint(str, sizeof str, "$%.17e", a->dval);
-		break;
+		return fmtprint(fp, "$%.17e", a->dval);
 
 	case D_SCONST:
-		snprint(str, sizeof str, "$\"%S\"", a->sval);
-		break;
+		return fmtprint(fp, "$\"%S\"", a->sval);
 	}
-	return fmtstrcpy(fp, str);
 }
 
 int
 Rconv(Fmt *fp)
 {
+	char str[STRINGSZ], *p, *e;
 	Adr *a;
 	int i, v;
 
@@ -200,14 +189,19 @@
 		if(a->sym != S)
 			break;
 		v = a->offset;
-		fmtprint(fp, "[");
+		p = str;
+		e = str+sizeof(str);
 		for(i=0; i<NREG; i++) {
-			if(v & (1<<i))
-				fmtprint(fp, "R%d,", i);
+			if(v & (1<<i)) {
+				if(p == str)
+					p = seprint(p, e, "[R%d", i);
+				else
+					p = seprint(p, e, ",R%d", i);
+			}
 		}
-		fmtprint(fp, "]");
+		seprint(p, e, "]");
 	}
-	return 0;
+	return fmtstrcpy(fp, str);
 }
 
 int
@@ -260,41 +254,30 @@
 int
 Nconv(Fmt *fp)
 {
-	char str[STRINGSZ];
 	Adr *a;
 	Sym *s;
 
 	a = va_arg(fp->args, Adr*);
 	s = a->sym;
-	if(s == S) {
-		snprint(str, sizeof str, "%ld", a->offset);
-		goto out;
-	}
+	if(s == S)
+		return fmtprint(fp, "%ld", a->offset);
 	switch(a->name) {
 	default:
-		snprint(str, sizeof str, "GOK-name(%d)", a->name);
-		break;
+		return fmtprint(fp, "GOK-name(%d)", a->name);
 
 	case D_NONE:
-		snprint(str, sizeof str, "%ld", a->offset);
-		break;
+		return fmtprint(fp, "%ld", a->offset);
 
 	case D_EXTERN:
-		snprint(str, sizeof str, "%s+%ld(SB)", s->name, a->offset);
-		break;
+		return fmtprint(fp, "%s+%ld(SB)", s->name, a->offset);
 
 	case D_STATIC:
-		snprint(str, sizeof str, "%s<>+%ld(SB)", s->name, a->offset);
-		break;
+		return fmtprint(fp, "%s<>+%ld(SB)", s->name, a->offset);
 
 	case D_AUTO:
-		snprint(str, sizeof str, "%s-%ld(SP)", s->name, -a->offset);
-		break;
+		return fmtprint(fp, "%s-%ld(SP)", s->name, -a->offset);
 
 	case D_PARAM:
-		snprint(str, sizeof str, "%s+%ld(FP)", s->name, a->offset);
-		break;
+		return fmtprint(fp, "%s+%ld(FP)", s->name, a->offset);
 	}
-out:
-	return fmtstrcpy(fp, str);
 }
--- a/sys/src/cmd/5c/mul.c
+++ b/sys/src/cmd/5c/mul.c
@@ -117,8 +117,7 @@
 	if(g) {
 		m1 = mulcon0(v);
 		if(m1) {
-			strcpy(m->code, m1->code);
-			sprint(strchr(m->code, 0), "%c0", g+'a');
+			snprint(m->code, sizeof(m->code), "%s%c0", m1->code, g+'a');
 			return m;
 		}
 	}
--- a/sys/src/cmd/5l/list.c
+++ b/sys/src/cmd/5l/list.c
@@ -21,7 +21,6 @@
 int
 Pconv(Fmt *fp)
 {
-	char str[STRINGSZ];
 	Prog *p;
 	int a;
 
@@ -31,31 +30,27 @@
 	switch(a) {
 	default:
 		if(p->reg == NREG)
-			snprint(str, sizeof str, "(%ld)	%A%C	%D,%D",
+			return fmtprint(fp, "(%ld)	%A%C	%D,%D",
 				p->line, a, p->scond, &p->from, &p->to);
 		else
 		if(p->from.type != D_FREG)
-			snprint(str, sizeof str, "(%ld)	%A%C	%D,R%d,%D",
+			return fmtprint(fp, "(%ld)	%A%C	%D,R%d,%D",
 				p->line, a, p->scond, &p->from, p->reg, &p->to);
 		else
-			snprint(str, sizeof str, "(%ld)	%A%C	%D,F%d,%D",
+			return fmtprint(fp, "(%ld)	%A%C	%D,F%d,%D",
 				p->line, a, p->scond, &p->from, p->reg, &p->to);
-		break;
 
 	case ASWPW:
 	case ASWPBU:
-		snprint(str, sizeof str, "(%ld)	%A%C	R%d,%D,%D",
+		return fmtprint(fp, "(%ld)	%A%C	R%d,%D,%D",
 			p->line, a, p->scond, p->reg, &p->from, &p->to);
-		break;
 
 	case ADATA:
 	case AINIT:
 	case ADYNT:
-		snprint(str, sizeof str, "(%ld)	%A%C	%D/%d,%D",
+		return fmtprint(fp, "(%ld)	%A%C	%D/%d,%D",
 			p->line, a, p->scond, &p->from, p->reg, &p->to);
-		break;
 	}
-	return fmtstrcpy(fp, str);
 }
 
 int
@@ -113,7 +108,6 @@
 int
 Dconv(Fmt *fp)
 {
-	char str[STRINGSZ];
 	char *op;
 	Adr *a;
 	long v;
@@ -120,132 +114,114 @@
 
 	a = va_arg(fp->args, Adr*);
 	switch(a->type) {
-
 	default:
-		snprint(str, sizeof str, "GOK-type(%d)", a->type);
-		break;
+		return fmtprint(fp, "GOK-type(%d)", a->type);
 
 	case D_NONE:
-		str[0] = 0;
 		if(a->name != D_NONE || a->reg != NREG || a->sym != S)
-			snprint(str, sizeof str, "%N(R%d)(NONE)", a, a->reg);
-		break;
+			return fmtprint(fp, "%N(R%d)(NONE)", a, a->reg);
+		return 0;
 
 	case D_CONST:
 		if(a->reg == NREG)
-			snprint(str, sizeof str, "$%N", a);
+			return fmtprint(fp, "$%N", a);
 		else
-			snprint(str, sizeof str, "$%N(R%d)", a, a->reg);
-		break;
+			return fmtprint(fp, "$%N(R%d)", a, a->reg);
 
 	case D_SHIFT:
 		v = a->offset;
 		op = "<<>>->@>" + (((v>>5) & 3) << 1);
 		if(v & (1<<4))
-			snprint(str, sizeof str, "R%ld%c%cR%ld", v&15, op[0], op[1], (v>>8)&15);
+			fmtprint(fp, "R%ld%c%cR%ld", v&15, op[0], op[1], (v>>8)&15);
 		else {
 			long sh = (v>>7)&31;
 			if(sh == 0 && (v & (3<<5)) != 0)
 				sh = 32;
-			snprint(str, sizeof str, "R%ld%c%c%ld", v&15, op[0], op[1], sh);
+			fmtprint(fp, "R%ld%c%c%ld", v&15, op[0], op[1], sh);
 		}
 		if(a->reg != NREG)
-			snprint(str+strlen(str), sizeof(str)-strlen(str), "(R%d)", a->reg);
-		break;
+			fmtprint(fp, "(R%d)", a->reg);
+		return 0;
 
 	case D_OCONST:
-		snprint(str, sizeof str, "$*$%N", a);
 		if(a->reg != NREG)
-			snprint(str, sizeof str, "%N(R%d)(CONST)", a, a->reg);
-		break;
+			return fmtprint(fp, "%N(R%d)(CONST)", a, a->reg);
+		else
+			return fmtprint(fp, "$*$%N", a);
 
 	case D_OREG:
 		if(a->reg != NREG)
-			snprint(str, sizeof str, "%N(R%d)", a, a->reg);
+			return fmtprint(fp, "%N(R%d)", a, a->reg);
 		else
-			snprint(str, sizeof str, "%N", a);
-		break;
+			return fmtprint(fp, "%N", a);
 
 	case D_REG:
-		snprint(str, sizeof str, "R%d", a->reg);
 		if(a->name != D_NONE || a->sym != S)
-			snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
-		break;
+			return fmtprint(fp, "%N(R%d)(REG)", a, a->reg);
+		else
+			return fmtprint(fp, "R%d", a->reg);
 
 	case D_REGREG:
-		snprint(str, sizeof str, "(R%d,R%d)", a->reg, (int)a->offset);
 		if(a->name != D_NONE || a->sym != S)
-			snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
-		break;
+			return fmtprint(fp, "%N(R%d)(REG)", a, a->reg);
+		else
+			return fmtprint(fp, "(R%d,R%d)", a->reg, (int)a->offset);
 
 	case D_FREG:
-		snprint(str, sizeof str, "F%d", a->reg);
 		if(a->name != D_NONE || a->sym != S)
-			snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
-		break;
+			return fmtprint(fp, "%N(R%d)(REG)", a, a->reg);
+		else
+			return fmtprint(fp, "F%d", a->reg);
 
 	case D_PSR:
+		if(a->name != D_NONE || a->sym != S)
+			return fmtprint(fp, "%N(PSR%d)(REG)", a, a->reg);
 		switch(a->reg) {
 		case 0:
-			snprint(str, sizeof str, "CPSR");
-			break;
+			return fmtprint(fp, "CPSR");
 		case 1:
-			snprint(str, sizeof str, "SPSR");
-			break;
+			return fmtprint(fp, "SPSR");
 		default:
-			snprint(str, sizeof str, "PSR%d", a->reg);
-			break;
+			return fmtprint(fp, "PSR%d", a->reg);
 		}
-		if(a->name != D_NONE || a->sym != S)
-			snprint(str, sizeof str, "%N(PSR%d)(REG)", a, a->reg);
-		break;
 
 	case D_FPCR:
+		if(a->name != D_NONE || a->sym != S)
+			return fmtprint(fp, "%N(FCR%d)(REG)", a, a->reg);
 		switch(a->reg){
 		case 0:
-			snprint(str, sizeof str, "FPSR");
-			break;
+			return fmtprint(fp, "FPSR");
 		case 1:
-			snprint(str, sizeof str, "FPCR");
-			break;
+			return fmtprint(fp, "FPCR");
 		default:
-			snprint(str, sizeof str, "FCR%d", a->reg);
-			break;
+			return fmtprint(fp, "FCR%d", a->reg);
 		}
-		if(a->name != D_NONE || a->sym != S)
-			snprint(str, sizeof str, "%N(FCR%d)(REG)", a, a->reg);
 
-		break;
-
 	case D_BRANCH:	/* botch */
 		if(curp->cond != P) {
 			v = curp->cond->pc;
 			if(a->sym != S)
-				snprint(str, sizeof str, "%s+%.5lux(BRANCH)", a->sym->name, v);
+				return fmtprint(fp, "%s+%.5lux(BRANCH)", a->sym->name, v);
 			else
-				snprint(str, sizeof str, "%.5lux(BRANCH)", v);
-		} else
+				return fmtprint(fp, "%.5lux(BRANCH)", v);
+		} else {
 			if(a->sym != S)
-				snprint(str, sizeof str, "%s+%ld(APC)", a->sym->name, a->offset);
+				return fmtprint(fp, "%s+%ld(APC)", a->sym->name, a->offset);
 			else
-				snprint(str, sizeof str, "%ld(APC)", a->offset);
-		break;
+				return fmtprint(fp, "%ld(APC)", a->offset);
+		}
 
 	case D_FCONST:
-		snprint(str, sizeof str, "$%e", ieeedtod(a->ieee));
-		break;
+		return fmtprint(fp, "$%e", ieeedtod(a->ieee));
 
 	case D_SCONST:
-		snprint(str, sizeof str, "$\"%S\"", a->sval);
-		break;
+		return fmtprint(fp, "$\"%S\"", a->sval);
 	}
-	return fmtstrcpy(fp, str);
 }
 
 int
 Nconv(Fmt *fp)
 {
-	char str[STRINGSZ];
 	Adr *a;
 	Sym *s;
 
@@ -253,42 +229,35 @@
 	s = a->sym;
 	switch(a->name) {
 	default:
-		snprint(str, sizeof str, "GOK-name(%d)", a->name);
-		break;
+		return fmtprint(fp, "GOK-name(%d)", a->name);
 
 	case D_NONE:
-		snprint(str, sizeof str, "%ld", a->offset);
-		break;
+		return fmtprint(fp, "%ld", a->offset);
 
 	case D_EXTERN:
 		if(s == S)
-			snprint(str, sizeof str, "%ld(SB)", a->offset);
+			return fmtprint(fp, "%ld(SB)", a->offset);
 		else
-			snprint(str, sizeof str, "%s+%ld(SB)", s->name, a->offset);
-		break;
+			return fmtprint(fp, "%s+%ld(SB)", s->name, a->offset);
 
 	case D_STATIC:
 		if(s == S)
-			snprint(str, sizeof str, "<>+%ld(SB)", a->offset);
+			return fmtprint(fp, "<>+%ld(SB)", a->offset);
 		else
-			snprint(str, sizeof str, "%s<>+%ld(SB)", s->name, a->offset);
-		break;
+			return fmtprint(fp, "%s<>+%ld(SB)", s->name, a->offset);
 
 	case D_AUTO:
 		if(s == S)
-			snprint(str, sizeof str, "%ld(SP)", a->offset);
+			return fmtprint(fp, "%ld(SP)", a->offset);
 		else
-			snprint(str, sizeof str, "%s-%ld(SP)", s->name, -a->offset);
-		break;
+			return fmtprint(fp, "%s-%ld(SP)", s->name, -a->offset);
 
 	case D_PARAM:
 		if(s == S)
-			snprint(str, sizeof str, "%ld(FP)", a->offset);
+			return fmtprint(fp, "%ld(FP)", a->offset);
 		else
-			snprint(str, sizeof str, "%s+%ld(FP)", s->name, a->offset);
-		break;
+			return fmtprint(fp, "%s+%ld(FP)", s->name, a->offset);
 	}
-	return fmtstrcpy(fp, str);
 }
 
 int
--- a/sys/src/cmd/6a/a.h
+++ b/sys/src/cmd/6a/a.h
@@ -151,7 +151,7 @@
 void	domacro(void);
 void	macund(void);
 void	macdef(void);
-void	macexpand(Sym*, char*);
+void	macexpand(Sym*, char*, int);
 void	macinc(void);
 void	macprag(void);
 void	maclin(void);
--- a/sys/src/cmd/6a/lex.c
+++ b/sys/src/cmd/6a/lex.c
@@ -38,7 +38,7 @@
 		break;
 	} ARGEND
 	if(*argv == 0) {
-		print("usage: %ca [-options] file.s\n", thechar);
+		print("usage: %Ca [-options] file.s\n", thechar);
 		errorexit();
 	}
 	if(argc > 1 && systemtype(Windows)){
@@ -92,10 +92,10 @@
 int
 assemble(char *file)
 {
-	char ofile[100], incfile[20], *p;
+	char *ofile, *p;
 	int i, of;
 
-	strcpy(ofile, file);
+	ofile = strdup(file);
 	p = utfrrune(ofile, pathchar());
 	if(p) {
 		include[0] = ofile;
@@ -103,16 +103,13 @@
 	} else
 		p = ofile;
 	if(outfile == 0) {
-		outfile = p;
-		if(outfile){
+		if(p){
+			outfile = p;
 			p = utfrrune(outfile, '.');
 			if(p)
 				if(p[1] == 's' && p[2] == 0)
 					p[0] = 0;
-			p = utfrune(outfile, 0);
-			p[0] = '.';
-			p[1] = thechar;
-			p[2] = 0;
+			outfile = smprint("%s.%C", outfile, thechar);
 		} else
 			outfile = "/dev/null";
 	}
@@ -120,15 +117,13 @@
 	if(p) {
 		setinclude(p);
 	} else {
-		if(systemtype(Plan9)) {
-			sprint(incfile,"/%s/include", thestring);
-			setinclude(strdup(incfile));
-		}
+		if(systemtype(Plan9))
+			setinclude(smprint("/%s/include", thestring));
 	}
 
 	of = mycreat(outfile, 0664);
 	if(of < 0) {
-		yyerror("%ca: cannot create %s", thechar, outfile);
+		yyerror("%Ca: cannot create %s", thechar, outfile);
 		errorexit();
 	}
 	Binit(&obuf, of, OWRITE);
--- a/sys/src/cmd/7a/a.h
+++ b/sys/src/cmd/7a/a.h
@@ -143,7 +143,7 @@
 void	domacro(void);
 void	macund(void);
 void	macdef(void);
-void	macexpand(Sym*, char*);
+void	macexpand(Sym*, char*, int);
 void	macinc(void);
 void	maclin(void);
 void	macprag(void);
--- a/sys/src/cmd/7a/lex.c
+++ b/sys/src/cmd/7a/lex.c
@@ -38,7 +38,7 @@
 		break;
 	} ARGEND
 	if(*argv == 0) {
-		print("usage: %ca [-options] file.s\n", thechar);
+		print("usage: %Ca [-options] file.s\n", thechar);
 		errorexit();
 	}
 	if(argc > 1 && systemtype(Windows)){
@@ -92,10 +92,10 @@
 int
 assemble(char *file)
 {
-	char ofile[100], incfile[20], *p;
+	char *ofile, *p;
 	int i, of;
 
-	strcpy(ofile, file);
+	ofile = strdup(file);
 	p = utfrrune(ofile, pathchar());
 	if(p) {
 		include[0] = ofile;
@@ -103,16 +103,13 @@
 	} else
 		p = ofile;
 	if(outfile == 0) {
-		outfile = p;
-		if(outfile){
+		if(p){
+			outfile = p;
 			p = utfrrune(outfile, '.');
 			if(p)
 				if(p[1] == 's' && p[2] == 0)
 					p[0] = 0;
-			p = utfrune(outfile, 0);
-			p[0] = '.';
-			p[1] = thechar;
-			p[2] = 0;
+			outfile = smprint("%s.%C", outfile, thechar);
 		} else
 			outfile = "/dev/null";
 	}
@@ -120,15 +117,13 @@
 	if(p) {
 		setinclude(p);
 	} else {
-		if(systemtype(Plan9)) {
-			sprint(incfile,"/%s/include", thestring);
-			setinclude(strdup(incfile));
-		}
+		if(systemtype(Plan9))
+			setinclude(smprint("/%s/include", thestring));
 	}
 
 	of = mycreat(outfile, 0664);
 	if(of < 0) {
-		yyerror("%ca: cannot create %s", thechar, outfile);
+		yyerror("%Ca: cannot create %s", thechar, outfile);
 		errorexit();
 	}
 	Binit(&obuf, of, OWRITE);
--- a/sys/src/cmd/7c/list.c
+++ b/sys/src/cmd/7c/list.c
@@ -17,27 +17,19 @@
 int
 Bconv(Fmt *fp)
 {
-	char str[STRINGSZ], ss[STRINGSZ], *s;
 	Bits bits;
 	int i;
 
-	str[0] = 0;
 	bits = va_arg(fp->args, Bits);
 	while(bany(&bits)) {
 		i = bnum(bits);
-		if(str[0])
-			strcat(str, " ");
-		if(var[i].sym == S) {
-			snprint(ss, sizeof(ss), "$%lld", var[i].offset);
-			s = ss;
-		} else
-			s = var[i].sym->name;
-		if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
-			break;
-		strcat(str, s);
 		bits.b[i/32] &= ~(1L << (i%32));
+		if(var[i].sym == S)
+			fmtprint(fp, "$%lld ", var[i].offset);
+		else
+			fmtprint(fp, "%s ", var[i].sym->name);
 	}
-	return fmtstrcpy(fp, str);
+	return 0;
 }
 
 static char *conds[] = {
@@ -88,7 +80,6 @@
 int
 Dconv(Fmt *fp)
 {
-	char str[STRINGSZ];
 	Adr *a;
 	char *op;
 	int v;
@@ -96,116 +87,97 @@
 
 	a = va_arg(fp->args, Adr*);
 	switch(a->type) {
-
 	default:
-		snprint(str, sizeof(str), "GOK-type(%d)", a->type);
-		break;
+		return fmtprint(fp, "GOK-type(%d)", a->type);
 
 	case D_NONE:
-		str[0] = 0;
 		if(a->name != D_NONE || a->reg != NREG || a->sym != S)
-			snprint(str, sizeof(str), "%N(R%d)(NONE)", a, a->reg);
-		break;
+			return fmtprint(fp, "%N(R%d)(NONE)", a, a->reg);
+		return 0;
 
 	case D_CONST:
 		if(a->reg != NREG)
-			snprint(str, sizeof(str), "$%N(R%d)", a, a->reg);
+			return fmtprint(fp, "$%N(R%d)", a, a->reg);
 		else
-			snprint(str, sizeof(str), "$%N", a);
-		break;
+			return fmtprint(fp, "$%N", a);
 
 	case D_SHIFT:
 		v = a->offset;
 		op = "<<>>->@>" + (((v>>5) & 3) << 1);
 		if(v & (1<<4))
-			snprint(str, sizeof(str), "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
+			fmtprint(fp, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
 		else
-			snprint(str, sizeof(str), "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
+			fmtprint(fp, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
 		if(a->reg != NREG)
-			sprint(str+strlen(str), "(R%d)", a->reg);
-		break;
+			fmtprint(fp, "(R%d)", a->reg);
+		return 0;
 
 	case D_OREG:
 		if(a->reg != NREG)
-			snprint(str, sizeof(str), "%N(R%d)", a, a->reg);
+			return fmtprint(fp, "%N(R%d)", a, a->reg);
 		else
-			snprint(str, sizeof(str), "%N", a);
-		break;
+			return fmtprint(fp, "%N", a);
 
 	case D_XPRE:
 		if(a->reg != NREG)
-			snprint(str, sizeof(str), "%N(R%d)!", a, a->reg);
+			return fmtprint(fp, "%N(R%d)!", a, a->reg);
 		else
-			snprint(str, sizeof(str), "%N!", a);
-		break;
+			return fmtprint(fp, "%N!", a);
 
 	case D_XPOST:
 		if(a->reg != NREG)
-			snprint(str, sizeof(str), "(R%d)%N!", a->reg, a);
+			return fmtprint(fp, "(R%d)%N!", a->reg, a);
 		else
-			snprint(str, sizeof(str), "%N!", a);
-		break;
+			return fmtprint(fp, "%N!", a);
 
 	case D_EXTREG:
 		v = a->offset;
 		if(v & (7<<10))
-			snprint(str, sizeof(str), "R%d%s<<%d", (v>>16)&31, extop[(v>>13)&7], (v>>10)&7);
+			return fmtprint(fp, "R%d%s<<%d", (v>>16)&31, extop[(v>>13)&7], (v>>10)&7);
 		else
-			snprint(str, sizeof(str), "R%d%s", (v>>16)&31, extop[(v>>13)&7]);
-		break;
+			return fmtprint(fp, "R%d%s", (v>>16)&31, extop[(v>>13)&7]);
 
 	case D_REG:
-		snprint(str, sizeof(str), "R%d", a->reg);
 		if(a->name != D_NONE || a->sym != S)
-			snprint(str, sizeof(str), "%N(R%d)(REG)", a, a->reg);
-		break;
+			return fmtprint(fp, "%N(R%d)(REG)", a, a->reg);
+		else
+			return fmtprint(fp, "R%d", a->reg);
 
 	case D_SP:
 		if(a->name != D_NONE || a->sym != S)
-			snprint(str, sizeof(str), "%N(R%d)(REG)", a, a->reg);
+			return fmtprint(fp, "%N(R%d)(REG)", a, a->reg);
 		else
-			strcpy(str, "SP");
-		break;
+			return fmtprint(fp, "SP");
 
 	case D_FREG:
-		snprint(str, sizeof(str), "F%d", a->reg);
 		if(a->name != D_NONE || a->sym != S)
-			snprint(str, sizeof(str), "%N(R%d)(REG)", a, a->reg);
-		break;
+			return fmtprint(fp, "%N(R%d)(REG)", a, a->reg);
+		else
+			return fmtprint(fp, "F%d", a->reg);
 
-
 	case D_SPR:
+		if(a->name != D_NONE || a->sym != S)
+			return fmtprint(fp, "%N(SPR(%lld))(REG)", a, a->offset);
 		switch((ulong)a->offset){
 		case D_FPSR:
-			sprint(str, "FPSR");
-			break;
+			return fmtprint(fp, "FPSR");
 		case D_FPCR:
-			sprint(str, "FPCR");
-			break;
+			return fmtprint(fp, "FPCR");
 		case D_NZCV:
-			sprint(str, "NZCV");
-			break;
+			return fmtprint(fp, "NZCV");
 		default:
-			sprint(str, "SPR(%#llux)", a->offset);
-			break;
+			return fmtprint(fp, "SPR(%#llux)", a->offset);
 		}
-		if(a->name != D_NONE || a->sym != S)
-			snprint(str, sizeof(str), "%N(SPR(%lld))(REG)", a, a->offset);
-		break;
 
 	case D_BRANCH:
-		snprint(str, sizeof(str), "%lld(PC)", a->offset-pc);
-		break;
+		return fmtprint(fp, "%lld(PC)", a->offset-pc);
 
 	case D_FCONST:
-		snprint(str, sizeof(str), "$%.17e", a->dval);
-		break;
+		return fmtprint(fp, "$%.17e", a->dval);
 
 	case D_SCONST:
-		snprint(str, sizeof(str), "$\"%S\"", a->sval);
-		break;
+		return fmtprint(fp, "$\"%S\"", a->sval);
 	}
-	return fmtstrcpy(fp, str);
 }
 
 int
@@ -289,41 +261,30 @@
 int
 Nconv(Fmt *fp)
 {
-	char str[STRINGSZ];
 	Adr *a;
 	Sym *s;
 
 	a = va_arg(fp->args, Adr*);
 	s = a->sym;
-	if(s == S) {
-		snprint(str, sizeof(str), "%lld", a->offset);
-		goto out;
-	}
+	if(s == S)
+		return fmtprint(fp, "%lld", a->offset);
 	switch(a->name) {
 	default:
-		snprint(str, sizeof(str), "GOK-name(%d)", a->name);
-		break;
+		return fmtprint(fp, "GOK-name(%d)", a->name);
 
 	case D_NONE:
-		snprint(str, sizeof(str), "%lld", a->offset);
-		break;
+		return fmtprint(fp, "%lld", a->offset);
 
 	case D_EXTERN:
-		snprint(str, sizeof(str), "%s+%lld(SB)", s->name, a->offset);
-		break;
+		return fmtprint(fp, "%s+%lld(SB)", s->name, a->offset);
 
 	case D_STATIC:
-		snprint(str, sizeof(str), "%s<>+%lld(SB)", s->name, a->offset);
-		break;
+		return fmtprint(fp, "%s<>+%lld(SB)", s->name, a->offset);
 
 	case D_AUTO:
-		snprint(str, sizeof(str), "%s-%lld(SP)", s->name, -a->offset);
-		break;
+		return fmtprint(fp, "%s-%lld(SP)", s->name, -a->offset);
 
 	case D_PARAM:
-		snprint(str, sizeof(str), "%s+%lld(FP)", s->name, a->offset);
-		break;
+		return fmtprint(fp, "%s+%lld(FP)", s->name, a->offset);
 	}
-out:
-	return fmtstrcpy(fp, str);
 }
--- a/sys/src/cmd/7c/mul.c
+++ b/sys/src/cmd/7c/mul.c
@@ -117,8 +117,7 @@
 	if(g) {
 		m1 = mulcon0(v);
 		if(m1) {
-			strcpy(m->code, m1->code);
-			sprint(strchr(m->code, 0), "%c0", g+'a');
+			snprint(m->code, sizeof(m->code), "%s%c0", m1->code, g+'a');
 			return m;
 		}
 	}
--- a/sys/src/cmd/7l/list.c
+++ b/sys/src/cmd/7l/list.c
@@ -15,7 +15,6 @@
 int
 Pconv(Fmt *fp)
 {
-	char str[STRINGSZ], *s;
 	Prog *p;
 	int a;
 
@@ -23,32 +22,28 @@
 	curp = p;
 	a = p->as;
 	switch(a) {
-	default:
-		s = str;
-		s += sprint(s, "(%ld)", p->line);
-		if(p->reg == NREG && p->from3.type == D_NONE)
-			sprint(s, "	%A	%D,%D",
-				a, &p->from, &p->to);
-		else if(p->from.type != D_FREG){
-			s += sprint(s, "	%A	%D", a, &p->from);
-			if(p->from3.type != D_NONE)
-				s += sprint(s, ",%D", &p->from3);
-			if(p->reg != NREG)
-				s += sprint(s, ",R%d", p->reg);
-			sprint(s, ",%D", &p->to);
-		}else
-			sprint(s, "	%A	%D,F%d,%D",
-				a, &p->from, p->reg, &p->to);
-		break;
-
 	case ADATA:
 	case AINIT:
 	case ADYNT:
-		sprint(str, "(%ld)	%A	%D/%d,%D",
+		return fmtprint(fp, "(%ld)	%A	%D/%d,%D",
 			p->line, a, &p->from, p->reg, &p->to);
-		break;
+
+	default:
+		if(p->reg == NREG && p->from3.type == D_NONE)
+			return fmtprint(fp, "(%ld)	%A	%D,%D",
+				p->line, a, &p->from, &p->to);
+		else if(p->from.type == D_FREG)
+			return fmtprint(fp, "(%ld)	%A	%D,F%d,%D",
+				p->line, a, &p->from, p->reg, &p->to);
+
+		fmtprint(fp, "(%ld)	%A	%D", p->line, a, &p->from);
+		if(p->from3.type != D_NONE)
+			fmtprint(fp, ",%D", &p->from3);
+		if(p->reg != NREG)
+			fmtprint(fp, ",R%d", p->reg);
+		fmtprint(fp, ",%D", &p->to);
+		return 0;
 	}
-	return fmtstrcpy(fp, str);
 }
 
 int
@@ -87,7 +82,6 @@
 int
 Dconv(Fmt *fp)
 {
-	char str[STRINGSZ];
 	char *op;
 	Adr *a;
 	long v;
@@ -97,144 +91,127 @@
 	switch(a->type) {
 
 	default:
-		sprint(str, "GOK-type(%d)", a->type);
-		break;
+		return fmtprint(fp, "GOK-type(%d)", a->type);
 
 	case D_NONE:
-		str[0] = 0;
 		if(a->name != D_NONE || a->reg != NREG || a->sym != S)
-			sprint(str, "%N(R%d)(NONE)", a, a->reg);
-		break;
+			return fmtprint(fp, "%N(R%d)(NONE)", a, a->reg);
+		return 0;
 
 	case D_CONST:
 		if(a->reg == NREG || a->reg == REGZERO)
-			sprint(str, "$%N", a);
+			return fmtprint(fp, "$%N", a);
 		else
-			sprint(str, "$%N(R%d)", a, a->reg);
-		break;
+			return fmtprint(fp, "$%N(R%d)", a, a->reg);
 
 	case D_SHIFT:
 		v = a->offset;
 		op = "<<>>->@>" + (((v>>22) & 3) << 1);
-		sprint(str, "R%ld%c%c%ld", (v>>16)&0x1F, op[0], op[1], (v>>10)&0x3F);
-		if(a->reg != NREG)
-			sprint(str+strlen(str), "(R%d)", a->reg);
-		break;
+		if(a->reg == NREG)
+			return fmtprint(fp, "R%ld%c%c%ld",
+				(v>>16)&0x1F, op[0], op[1], (v>>10)&0x3F);
+		else
+			return fmtprint(fp, "R%ld%c%c%ld(R%d)",
+				(v>>16)&0x1F, op[0], op[1], (v>>10)&0x3F, a->reg);
 
 	case D_OCONST:
-		sprint(str, "$*$%N", a);
 		if(a->reg != NREG)
-			sprint(str, "%N(R%d)(CONST)", a, a->reg);
-		break;
+			return fmtprint(fp, "$*$%N(R%d)(CONST)", a, a->reg);
+		else
+			return fmtprint(fp, "$*$%N", a);
 
 	case D_OREG:
 		if(a->reg != NREG)
-			sprint(str, "%N(R%d)", a, a->reg);
+			return fmtprint(fp, "%N(R%d)", a, a->reg);
 		else
-			sprint(str, "%N", a);
-		break;
+			return fmtprint(fp, "%N", a);
 
 	case D_XPRE:
 		if(a->reg != NREG)
-			sprint(str, "%N(R%d)!", a, a->reg);
+			return fmtprint(fp, "%N(R%d)!", a, a->reg);
 		else
-			sprint(str, "%N!", a);
-		break;
+			return fmtprint(fp, "%N!", a);
 
 	case D_XPOST:
 		if(a->reg != NREG)
-			sprint(str, "(R%d)%N!", a->reg, a);
+			return fmtprint(fp, "(R%d)%N!", a->reg, a);
 		else
-			sprint(str, "%N!", a);
-		break;
+			return fmtprint(fp, "%N!", a);
 
 	case D_EXTREG:
 		v = a->offset;
 		if(v & (7<<10))
-			snprint(str, sizeof(str), "R%ld%s<<%ld", (v>>16)&31, extop[(v>>13)&7], (v>>10)&7);
+			return fmtprint(fp, "R%ld%s<<%ld", (v>>16)&31, extop[(v>>13)&7], (v>>10)&7);
 		else
-			snprint(str, sizeof(str), "R%ld%s", (v>>16)&31, extop[(v>>13)&7]);
-		break;
+			return fmtprint(fp, "R%ld%s", (v>>16)&31, extop[(v>>13)&7]);
 
 	case D_ROFF:
 		v = a->offset;
 		if(v & (1<<16))
-			snprint(str, sizeof(str), "(R%d)[R%ld%s]", a->reg, v&31, extop[(v>>8)&7]);
+			return fmtprint(fp, "(R%d)[R%ld%s]", a->reg, v&31, extop[(v>>8)&7]);
 		else
-			snprint(str, sizeof(str), "(R%d)(R%ld%s)", a->reg, v&31, extop[(v>>8)&7]);
-		break;
+			return fmtprint(fp, "(R%d)(R%ld%s)", a->reg, v&31, extop[(v>>8)&7]);
 
 	case D_REG:
-		sprint(str, "R%d", a->reg);
 		if(a->name != D_NONE || a->sym != S)
-			sprint(str, "%N(R%d)(REG)", a, a->reg);
-		break;
+			return fmtprint(fp, "%N(R%d)(REG)", a, a->reg);
+		else
+			return fmtprint(fp, "R%d", a->reg);
 
 	case D_SP:
 		if(a->name != D_NONE || a->sym != S)
-			sprint(str, "%N(R%d)(REG)", a, a->reg);
+			return fmtprint(fp, "%N(R%d)(REG)", a, a->reg);
 		else
-			strcpy(str, "SP");
-		break;
+			return fmtprint(fp, "SP");
 
 	case D_COND:
-		strcpy(str, strcond[a->reg & 0xF]);
-		break;
+		return fmtprint(fp, "%s", strcond[a->reg & 0xF]);
 
 	case D_FREG:
-		sprint(str, "F%d", a->reg);
 		if(a->name != D_NONE || a->sym != S)
-			sprint(str, "%N(R%d)(REG)", a, a->reg);
-		break;
+			return fmtprint(fp, "%N(R%d)(REG)", a, a->reg);
+		else
+			return fmtprint(fp, "F%d", a->reg);
 
 	case D_SPR:
+		if(a->name != D_NONE || a->sym != S)
+			return fmtprint(fp, "%N(SPR%lld)(REG)", a, a->offset);
 		switch((ulong)a->offset){
 		case D_FPSR:
-			sprint(str, "FPSR");
-			break;
+			return fmtprint(fp, "FPSR");
 		case D_FPCR:
-			sprint(str, "FPCR");
-			break;
+			return fmtprint(fp, "FPCR");
 		case D_NZCV:
-			sprint(str, "NZCV");
-			break;
+			return fmtprint(fp, "NZCV");
 		default:
-			sprint(str, "SPR(%#llux)", a->offset);
-			break;
+			return fmtprint(fp, "SPR(%#llux)", a->offset);
 		}
-		if(a->name != D_NONE || a->sym != S)
-			sprint(str, "%N(SPR%lld)(REG)", a, a->offset);
-		break;
 
 	case D_BRANCH:	/* botch */
 		if(curp->cond != P) {
 			v = curp->cond->pc;
 			if(a->sym != S)
-				sprint(str, "%s+%#.5lux(BRANCH)", a->sym->name, v);
+				return fmtprint(fp, "%s+%#.5lux(BRANCH)", a->sym->name, v);
 			else
-				sprint(str, "%.5lux(BRANCH)", v);
-		} else
+				return fmtprint(fp, "%.5lux(BRANCH)", v);
+		} else {
 			if(a->sym != S)
-				sprint(str, "%s+%lld(APC)", a->sym->name, a->offset);
+				return fmtprint(fp, "%s+%lld(APC)", a->sym->name, a->offset);
 			else
-				sprint(str, "%lld(APC)", a->offset);
-		break;
+				return fmtprint(fp, "%lld(APC)", a->offset);
+		}
 
 	case D_FCONST:
-		sprint(str, "$%e", ieeedtod(a->ieee));
-		break;
+		return fmtprint(fp, "$%e", ieeedtod(a->ieee));
 
 	case D_SCONST:
-		sprint(str, "$\"%S\"", a->sval);
-		break;
+		return fmtprint(fp, "$\"%S\"", a->sval);
 	}
-	return fmtstrcpy(fp, str);
 }
 
 int
 Nconv(Fmt *fp)
 {
-	char str[STRINGSZ];
 	Adr *a;
 	Sym *s;
 
@@ -242,42 +219,35 @@
 	s = a->sym;
 	switch(a->name) {
 	default:
-		sprint(str, "GOK-name(%d)", a->name);
-		break;
+		return fmtprint(fp, "GOK-name(%d)", a->name);
 
 	case D_NONE:
-		sprint(str, "%lld", a->offset);
-		break;
+		return fmtprint(fp, "%lld", a->offset);
 
 	case D_EXTERN:
 		if(s == S)
-			sprint(str, "%lld(SB)", a->offset);
+			return fmtprint(fp, "%lld(SB)", a->offset);
 		else
-			sprint(str, "%s+%lld(SB)", s->name, a->offset);
-		break;
+			return fmtprint(fp, "%s+%lld(SB)", s->name, a->offset);
 
 	case D_STATIC:
 		if(s == S)
-			sprint(str, "<>+%lld(SB)", a->offset);
+			return fmtprint(fp, "<>+%lld(SB)", a->offset);
 		else
-			sprint(str, "%s<>+%lld(SB)", s->name, a->offset);
-		break;
+			return fmtprint(fp, "%s<>+%lld(SB)", s->name, a->offset);
 
 	case D_AUTO:
 		if(s == S)
-			sprint(str, "%lld(SP)", a->offset);
+			return fmtprint(fp, "%lld(SP)", a->offset);
 		else
-			sprint(str, "%s-%lld(SP)", s->name, -a->offset);
-		break;
+			return fmtprint(fp, "%s-%lld(SP)", s->name, -a->offset);
 
 	case D_PARAM:
 		if(s == S)
-			sprint(str, "%lld(FP)", a->offset);
+			return fmtprint(fp, "%lld(FP)", a->offset);
 		else
-			sprint(str, "%s+%lld(FP)", s->name, a->offset);
-		break;
+			return fmtprint(fp, "%s+%lld(FP)", s->name, a->offset);
 	}
-	return fmtstrcpy(fp, str);
 }
 
 int
--- a/sys/src/cmd/7l/obj.c
+++ b/sys/src/cmd/7l/obj.c
@@ -1019,7 +1019,7 @@
 
 		if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) {
 			/* size sb 9 max */
-			sprint(literal, "$%lux", ieeedtof(p->from.ieee));
+			snprint(literal, sizeof(literal), "$%lux", ieeedtof(p->from.ieee));
 			s = lookup(literal, 0);
 			if(s->type == 0) {
 				s->type = SBSS;
@@ -1048,7 +1048,7 @@
 
 		if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) {
 			/* size sb 18 max */
-			sprint(literal, "$%lux.%lux",
+			snprint(literal, sizeof(literal), "$%lux.%lux",
 				p->from.ieee->l, p->from.ieee->h);
 			s = lookup(literal, 0);
 			if(s->type == 0) {
--- a/sys/src/cmd/8a/a.h
+++ b/sys/src/cmd/8a/a.h
@@ -152,7 +152,7 @@
 void	domacro(void);
 void	macund(void);
 void	macdef(void);
-void	macexpand(Sym*, char*);
+void	macexpand(Sym*, char*, int);
 void	macinc(void);
 void	macprag(void);
 void	maclin(void);
--- a/sys/src/cmd/8a/lex.c
+++ b/sys/src/cmd/8a/lex.c
@@ -38,7 +38,7 @@
 		break;
 	} ARGEND
 	if(*argv == 0) {
-		print("usage: %ca [-options] file.s\n", thechar);
+		print("usage: %Ca [-options] file.s\n", thechar);
 		errorexit();
 	}
 	if(argc > 1 && systemtype(Windows)){
@@ -92,10 +92,10 @@
 int
 assemble(char *file)
 {
-	char ofile[100], incfile[20], *p;
+	char *ofile, *p;
 	int i, of;
 
-	strcpy(ofile, file);
+	ofile = strdup(file);
 	p = utfrrune(ofile, pathchar());
 	if(p) {
 		include[0] = ofile;
@@ -103,16 +103,13 @@
 	} else
 		p = ofile;
 	if(outfile == 0) {
-		outfile = p;
-		if(outfile){
+		if(p){
+			outfile = p;
 			p = utfrrune(outfile, '.');
 			if(p)
 				if(p[1] == 's' && p[2] == 0)
 					p[0] = 0;
-			p = utfrune(outfile, 0);
-			p[0] = '.';
-			p[1] = thechar;
-			p[2] = 0;
+			outfile = smprint("%s.%C", outfile, thechar);
 		} else
 			outfile = "/dev/null";
 	}
@@ -120,15 +117,13 @@
 	if(p) {
 		setinclude(p);
 	} else {
-		if(systemtype(Plan9)) {
-			sprint(incfile,"/%s/include", thestring);
-			setinclude(strdup(incfile));
-		}
+		if(systemtype(Plan9))
+			setinclude(smprint("/%s/include", thestring));
 	}
 
 	of = mycreat(outfile, 0664);
 	if(of < 0) {
-		yyerror("%ca: cannot create %s", thechar, outfile);
+		yyerror("%Ca: cannot create %s", thechar, outfile);
 		errorexit();
 	}
 	Binit(&obuf, of, OWRITE);
--- a/sys/src/cmd/8c/list.c
+++ b/sys/src/cmd/8c/list.c
@@ -34,20 +34,18 @@
 int
 Pconv(Fmt *fp)
 {
-	char str[STRINGSZ];
 	Prog *p;
 
 	p = va_arg(fp->args, Prog*);
 	if(p->as == ADATA)
-		snprint(str, sizeof(str), "	%A	%D/%d,%D",
+		return fmtprint(fp, "	%A	%D/%d,%D",
 			p->as, &p->from, p->from.scale, &p->to);
 	else if(p->as == ATEXT)
-		snprint(str, sizeof(str), "	%A	%D,%d,%D",
+		return fmtprint(fp, "	%A	%D,%d,%D",
 			p->as, &p->from, p->from.scale, &p->to);
 	else
-		snprint(str, sizeof(str), "	%A	%D,%D",
+		return fmtprint(fp, "	%A	%D,%D",
 			p->as, &p->from, &p->to);
-	return fmtstrcpy(fp, str);
 }
 
 int
@@ -213,16 +211,13 @@
 int
 Rconv(Fmt *fp)
 {
-	char str[20];
 	int r;
 
 	r = va_arg(fp->args, int);
 	if(r >= D_AL && r <= D_NONE)
-		snprint(str, sizeof(str), "%s", regstr[r-D_AL]);
+		return fmtprint(fp, "%s", regstr[r-D_AL]);
 	else
-		snprint(str, sizeof(str), "gok(%d)", r);
-
-	return fmtstrcpy(fp, str);
+		return fmtprint(fp, "gok(%d)", r);
 }
 
 int
--- a/sys/src/cmd/cc/cc.h
+++ b/sys/src/cmd/cc/cc.h
@@ -554,7 +554,7 @@
 void	macdef(void);
 void	macprag(void);
 void	macend(void);
-void	macexpand(Sym*, char*);
+void	macexpand(Sym*, char*, int);
 void	macif(int);
 void	macinc(void);
 void	maclin(void);
--- a/sys/src/cmd/cc/funct.c
+++ b/sys/src/cmd/cc/funct.c
@@ -217,7 +217,6 @@
 	Node *n;
 	Type *f1, *f2, *f3, *f4;
 	int o, i, c;
-	char str[100];
 
 	if(t->funct)
 		return;
@@ -262,9 +261,9 @@
 		o = ftabinit[i].op;
 		if(o == OXXX)
 			break;
-		sprint(str, "%s_%s_", t->tag->name, ftabinit[i].name);
+		snprint(symb, NSYMB, "%s_%s_", t->tag->name, ftabinit[i].name);
 		n = new(ONAME, Z, Z);
-		n->sym = slookup(str);
+		n->sym = lookup();
 		f->sym[o] = n->sym;
 		switch(ftabinit[i].typ) {
 		default:
@@ -296,9 +295,9 @@
 		/*
 		 * OCAST types T1 _T2_T1_(T2)
 		 */
-		sprint(str, "_%s%s_", gtabinit[i].name, t->tag->name);
+		snprint(symb, NSYMB, "_%s%s_", gtabinit[i].name, t->tag->name);
 		n = new(ONAME, Z, Z);
-		n->sym = slookup(str);
+		n->sym = lookup();
 		f->castto[o] = n->sym;
 
 		f1 = typ(TFUNC, t);
@@ -305,9 +304,9 @@
 		f1->down = types[o];
 		dodecl(xdecl, CEXTERN, f1, n);
 
-		sprint(str, "%s_%s_", t->tag->name, gtabinit[i].name);
+		snprint(symb, NSYMB, "%s_%s_", t->tag->name, gtabinit[i].name);
 		n = new(ONAME, Z, Z);
-		n->sym = slookup(str);
+		n->sym = lookup();
 		f->castfr[o] = n->sym;
 
 		f1 = typ(TFUNC, types[o]);
--- a/sys/src/cmd/cc/lex.c
+++ b/sys/src/cmd/cc/lex.c
@@ -60,7 +60,7 @@
 void
 main(int argc, char *argv[])
 {
-	char *defs[50], *p;
+	char **defs, *p;
 	int nproc, nout, status, i, c, ndef;
 
 	memset(debug, 0, sizeof(debug));
@@ -71,6 +71,7 @@
 
 	profileflg = 1;	/* #pragma can turn it off */
 	tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
+	defs = 0;
 	ndef = 0;
 	outfile = 0;
 	include[ninclude++] = ".";
@@ -97,6 +98,8 @@
 	case 'D':
 		p = ARGF();
 		if(p) {
+			if((ndef & 15) == 0)
+				defs = allocn(defs, ndef*sizeof(defs[0]), 16*sizeof(defs[0]));
 			defs[ndef++] = p;
 			dodefine(p);
 		}
@@ -109,7 +112,7 @@
 		break;
 	} ARGEND
 	if(argc < 1 && outfile == 0) {
-		print("usage: %cc [-options] files\n", thechar);
+		print("usage: %Cc [-options] files\n", thechar);
 		errorexit();
 	}
 	if(argc > 1 && systemtype(Windows)){
@@ -176,12 +179,11 @@
 int
 compile(char *file, char **defs, int ndef)
 {
-	char ofile[400], incfile[20];
-	char *p, *av[100], opt[256];
+	char *ofile, *p, **av;
 	int i, c, fd[2];
 	static int first = 1;
 
-	strcpy(ofile, file);
+	ofile = strdup(file);
 	p = utfrrune(ofile, pathchar());
 	if(p) {
 		*p++ = 0;
@@ -191,21 +193,17 @@
 		p = ofile;
 
 	if(outfile == 0) {
-		outfile = p;
-		if(outfile) {
+		if(p) {
+			outfile = p;
 			if(p = utfrrune(outfile, '.'))
 				if(p[1] == 'c' && p[2] == 0)
 					p[0] = 0;
-			p = utfrune(outfile, 0);
 			if(debug['a'] && debug['n'])
-				strcat(p, ".acid");
+				outfile = smprint("%s.acid", outfile);
 			else if(debug['Z'] && debug['n'])
-				strcat(p, "_pickle.c");
-			else {
-				p[0] = '.';
-				p[1] = thechar;
-				p[2] = 0;
-			}
+				outfile = smprint("%s_pickle.c", outfile);
+			else
+				outfile = smprint("%s.%C", outfile, thechar);
 		} else
 			outfile = "/dev/null";
 	}
@@ -214,8 +212,7 @@
 		setinclude(p);
 	} else {
 		if(systemtype(Plan9)) {
-			sprint(incfile, "/%s/include", thestring);
-			setinclude(strdup(incfile));
+			setinclude(smprint("/%s/include", thestring));
 			setinclude("/sys/include");
 		}
 	}
@@ -265,22 +262,19 @@
 			close(fd[0]);
 			mydup(fd[1], 1);
 			close(fd[1]);
-			av[0] = CPP;
-			i = 1;
-			sprint(opt, "-+");
-			av[i++] = strdup(opt);
-			if(debug['.']){
-				sprint(opt, "-.");
-				av[i++] = strdup(opt);
-			}
-			for(c = 0; c < ndef; c++) {
-				sprint(opt, "-D%s", defs[c]);
-				av[i++] = strdup(opt);
-			}
-			for(c = 0; c < ninclude; c++) {
-				sprint(opt, "-I%s", include[c]);
-				av[i++] = strdup(opt);
-			}
+
+			i = 8+ndef+ninclude;
+			av = alloc(i*sizeof(av[0]));
+
+			i = 0;
+			av[i++] = CPP;
+			av[i++] = "-+";
+			if(debug['.'])
+				av[i++] = "-.";
+			for(c = 0; c < ndef; c++)
+				av[i++] = smprint("-D%s", defs[c]);
+			for(c = 0; c < ninclude; c++)
+				av[i++] = smprint("-I%s", include[c]);
 			if(strcmp(file, "stdin") != 0)
 				av[i++] = file;
 			av[i] = 0;
@@ -367,7 +361,7 @@
 	if(f < 0)
 		i->f = open(s, 0);
 	if(i->f < 0) {
-		yyerror("%cc: %r: %s", thechar, s);
+		yyerror("%Cc: %r: %s", thechar, s);
 		errorexit();
 	}
 	fi.c = 0;
@@ -377,8 +371,11 @@
 Sym*
 slookup(char *s)
 {
-
-	strcpy(symb, s);
+	strncpy(symb, s, NSYMB);
+	if(symb[NSYMB-1] != '\0'){
+		yyerror("symbol too long: %s", s);
+		errorexit();
+	}
 	return lookup();
 }
 
@@ -410,7 +407,6 @@
 	s->name = alloc(n);
 	memmove(s->name, symb, n);
 
-	strcpy(s->name, symb);
 	s->link = hash[h];
 	hash[h] = s;
 	syminit(s);
@@ -760,7 +756,7 @@
 	if(s->macro) {
 		newio();
 		cp = ionext->b;
-		macexpand(s, cp);
+		macexpand(s, cp, sizeof(ionext->b));
 		pushio();
 		ionext->link = iostack;
 		iostack = ionext;
@@ -1341,7 +1337,6 @@
 int
 Lconv(Fmt *fp)
 {
-	char str[STRINGSZ], s[STRINGSZ];
 	Hist *h;
 	struct
 	{
@@ -1383,87 +1378,62 @@
 	}
 	if(n > HISTSZ)
 		n = HISTSZ;
-	str[0] = 0;
+	if(n == 0)
+		return fmtprint(fp, "<eof>");
 	for(i=n-1; i>=0; i--) {
 		if(i != n-1) {
 			if(fp->flags & ~(FmtWidth|FmtPrec))	/* BUG ROB - was f3 */
 				break;
-			strcat(str, " ");
+			fmtrune(fp, ' ');
 		}
 		if(a[i].line)
-			snprint(s, STRINGSZ, "%s:%ld[%s:%ld]",
+			fmtprint(fp, "%s:%ld[%s:%ld]",
 				a[i].line->name, l-a[i].ldel+1,
 				a[i].incl->name, l-a[i].idel+1);
 		else
-			snprint(s, STRINGSZ, "%s:%ld",
+			fmtprint(fp, "%s:%ld",
 				a[i].incl->name, l-a[i].idel+1);
-		if(strlen(s)+strlen(str) >= STRINGSZ-10)
-			break;
-		strcat(str, s);
 		l = a[i].incl->line - 1;	/* now print out start of this file */
 	}
-	if(n == 0)
-		strcat(str, "<eof>");
-	return fmtstrcpy(fp, str);
+	return 0;
 }
 
 int
 Tconv(Fmt *fp)
 {
-	char str[STRINGSZ+20], s[STRINGSZ+20];
 	Type *t, *t1;
 	int et;
 	long n;
 
-	str[0] = 0;
-	for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
+	t = va_arg(fp->args, Type*);
+	while(t != T) {
+		if(t->garb&~GINCOMPLETE)
+			fmtprint(fp, "%s ", gnames[t->garb&~GINCOMPLETE]);
 		et = t->etype;
-		if(str[0])
-			strcat(str, " ");
-		if(t->garb&~GINCOMPLETE) {
-			sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]);
-			if(strlen(str) + strlen(s) < STRINGSZ)
-				strcat(str, s);
+		fmtprint(fp, "%s", tnames[et]);
+		if(et == TFUNC && (t1 = t->down) != T) {
+			fmtprint(fp, "(%T", t1);
+			while((t1 = t1->down) != T)
+				fmtprint(fp, ", %T", t1);
+			fmtprint(fp, ")");
 		}
-		sprint(s, "%s", tnames[et]);
-		if(strlen(str) + strlen(s) < STRINGSZ)
-			strcat(str, s);
-		if(et == TFUNC && (t1 = t->down)) {
-			sprint(s, "(%T", t1);
-			if(strlen(str) + strlen(s) < STRINGSZ)
-				strcat(str, s);
-			while(t1 = t1->down) {
-				sprint(s, ", %T", t1);
-				if(strlen(str) + strlen(s) < STRINGSZ)
-					strcat(str, s);
-			}
-			if(strlen(str) + strlen(s) < STRINGSZ)
-				strcat(str, ")");
-		}
 		if(et == TARRAY) {
 			n = t->width;
-			if(t->link && t->link->width)
+			if(t->link != T && t->link->width)
 				n /= t->link->width;
-			sprint(s, "[%ld]", n);
-			if(strlen(str) + strlen(s) < STRINGSZ)
-				strcat(str, s);
+			fmtprint(fp, "[%ld]", n);
 		}
-		if(t->nbits) {
-			sprint(s, " %d:%d", t->shift, t->nbits);
-			if(strlen(str) + strlen(s) < STRINGSZ)
-				strcat(str, s);
-		}
+		if(t->nbits)
+			fmtprint(fp, " %d:%d", t->shift, t->nbits);
 		if(typesu[et]) {
-			if(t->tag) {
-				strcat(str, " ");
-				if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
-					strcat(str, t->tag->name);
-			} else
-				strcat(str, " {}");
+			fmtprint(fp, " %s", t->tag? t->tag->name: "{}");
 			break;
 		}
+		if((t = t->link) == T)
+			break;
+		fmtrune(fp, ' ');
 	}
-	return fmtstrcpy(fp, str);
+	return 0;
 }
 
 int
@@ -1482,46 +1452,36 @@
 int
 Qconv(Fmt *fp)
 {
-	char str[STRINGSZ+20], *s;
 	long b;
 	int i;
 
-	str[0] = 0;
-	for(b = va_arg(fp->args, long); b;) {
+	b = va_arg(fp->args, long);
+	while(b) {
 		i = bitno(b);
-		if(str[0])
-			strcat(str, " ");
-		s = qnames[i];
-		if(strlen(str) + strlen(s) >= STRINGSZ)
-			break;
-		strcat(str, s);
 		b &= ~(1L << i);
+		fmtprint(fp, "%s%s", qnames[i], b? " ": "");
 	}
-	return fmtstrcpy(fp, str);
+	return 0;
 }
 
 int
 VBconv(Fmt *fp)
 {
-	char str[STRINGSZ];
-	int i, n, t, pc;
+	int n, t, pc;
 
 	n = va_arg(fp->args, int);
 	pc = 0;	/* BUG: was printcol */
-	i = 0;
 	while(pc < n) {
 		t = (pc+4) & ~3;
 		if(t <= n) {
-			str[i++] = '\t';
+			fmtrune(fp, '\t');
 			pc = t;
-			continue;
+		} else {
+			fmtrune(fp, ' ');
+			pc++;
 		}
-		str[i++] = ' ';
-		pc++;
 	}
-	str[i] = 0;
-
-	return fmtstrcpy(fp, str);
+	return 0;
 }
 
 void
--- a/sys/src/cmd/cc/lexbody
+++ b/sys/src/cmd/cc/lexbody
@@ -111,7 +111,7 @@
 	if(f < 0)
 		i->f = open(s, 0);
 	if(i->f < 0) {
-		yyerror("%ca: %r: %s", thechar, s);
+		yyerror("%Ca: %r: %s", thechar, s);
 		errorexit();
 	}
 	fi.c = 0;
@@ -121,8 +121,11 @@
 Sym*
 slookup(char *s)
 {
-
-	strcpy(symb, s);
+	strncpy(symb, s, NSYMB);
+	if(symb[NSYMB-1] != '\0'){
+		yyerror("symbol too long: %s", s);
+		errorexit();
+	}
 	return lookup();
 }
 
@@ -130,15 +133,17 @@
 lookup(void)
 {
 	Sym *s;
-	long h;
+	ulong h;
 	char *p;
-	int c, l;
+	int c, n;
 
 	h = 0;
-	for(p=symb; c = *p; p++)
-		h = h+h+h + c;
-	l = (p - symb) + 1;
-	if(h < 0)
+	for(p=symb; *p;) {
+		h = h * 3;
+		h += *p++;
+	}
+	n = (p - symb) + 1;
+	if((long)h < 0)
 		h = ~h;
 	h %= NHASH;
 	c = symb[0];
@@ -145,16 +150,17 @@
 	for(s = hash[h]; s != S; s = s->link) {
 		if(s->name[0] != c)
 			continue;
-		if(memcmp(s->name, symb, l) == 0)
+		if(strcmp(s->name, symb) == 0)
 			return s;
 	}
 	s = alloc(sizeof(*s));
-	s->name = alloc(l);
-	memmove(s->name, symb, l);
+	s->name = alloc(n);
+	memmove(s->name, symb, n);
 
 	s->link = hash[h];
 	hash[h] = s;
 	syminit(s);
+
 	return s;
 }
 
@@ -220,6 +226,8 @@
 		cp = symb;
 
 	aloop:
+		if(cp >= &symb[NSYMB-1])
+			goto toolong;
 		*cp++ = c;
 		c = GETC();
 		if(isalpha(c) || isdigit(c) || c == '_' || c == '$')
@@ -230,7 +238,7 @@
 		if(s->macro) {
 			newio();
 			cp = ionext->b;
-			macexpand(s, cp);
+			macexpand(s, cp, sizeof(ionext->b));
 			pushio();
 			ionext->link = iostack;
 			iostack = ionext;
@@ -295,6 +303,8 @@
 		for(;;) {
 			if(!isdigit(c))
 				break;
+			if(cp >= &symb[NSYMB-1])
+				goto toolong;
 			*cp++ = c;
 			c = GETC();
 		}
@@ -316,6 +326,8 @@
 
 	casedot:
 		for(;;) {
+			if(cp >= &symb[NSYMB-1])
+				goto toolong;
 			*cp++ = c;
 			c = GETC();
 			if(!isdigit(c))
@@ -326,13 +338,19 @@
 		goto caseout;
 
 	casee:
+		if(cp >= &symb[NSYMB-1])
+			goto toolong;
 		*cp++ = 'e';
 		c = GETC();
 		if(c == '+' || c == '-') {
+			if(cp >= &symb[NSYMB-1])
+				goto toolong;
 			*cp++ = c;
 			c = GETC();
 		}
 		while(isdigit(c)) {
+			if(cp >= &symb[NSYMB-1])
+				goto toolong;
 			*cp++ = c;
 			c = GETC();
 		}
@@ -409,6 +427,10 @@
 	}
 	peekc = c1;
 	return c;
+toolong:
+	yyerror("token too long: %.*s...", utfnlen(symb, cp-symb), symb);
+	errorexit();
+	return -1;
 }
 
 int
--- a/sys/src/cmd/cc/macbody
+++ b/sys/src/cmd/cc/macbody
@@ -128,7 +128,11 @@
 	char *p;
 	long l;
 
-	strcpy(symb, cp);
+	strncpy(symb, cp, NSYMB);
+	if(symb[NSYMB-1] != '\0'){
+		yyerror("macro too long: %s", cp);
+		symb[NSYMB-1] = 0;
+	}
 	p = strchr(symb, '=');
 	if(p) {
 		*p++ = 0;
@@ -376,17 +380,16 @@
 }
 
 void
-macexpand(Sym *s, char *b)
+macexpand(Sym *s, char *b, int blen)
 {
 	char buf[2000];
 	int n, l, c, nargs;
-	char *arg[NARG], *cp, *ob, *ecp, dots;
+	char *arg[NARG], *cp, *ob, *eb, *ecp, dots;
 
-	ob = b;
 	if(*s->macro == 0) {
-		strcpy(b, s->macro+1);
+		strncpy(b, s->macro+1, blen);
 		if(debug['m'])
-			print("#expand %s %s\n", s->name, ob);
+			print("#expand %s %s\n", s->name, b);
 		return;
 	}
 	
@@ -493,8 +496,12 @@
 		*b = 0;
 		return;
 	}
+	ob = b;
+	eb = b + blen-1;
 	cp = s->macro+1;
 	for(;;) {
+		if(b >= eb)
+			goto toobig;
 		c = *cp++;
 		if(c == '\n')
 			c = ' ';
@@ -514,8 +521,11 @@
 		c -= 'a';
 		if(c < 0 || c >= n)
 			continue;
-		strcpy(b, arg[c]);
-		b += strlen(arg[c]);
+		l = strlen(arg[c]);
+		if(b+l > eb)
+			goto toobig;
+		memmove(b, arg[c], l);
+		b += l;
 	}
 	*b = 0;
 	if(debug['m'])
@@ -551,6 +561,10 @@
 			break;
 		if(c == '\n')
 			goto bad;
+		if(hp >= &str[STRINGSZ-1]){
+			yyerror("name too long for #include");
+			break;
+		}
 		*hp++ = c;
 	}
 	*hp = 0;
@@ -558,29 +572,28 @@
 	c = getcom();
 	if(c != '\n')
 		goto bad;
-
 	f = -1;
+	c = 0;
 	for(i=0; i<ninclude; i++) {
 		if(i == 0 && c0 == '>')
 			continue;
-		strcpy(symb, include[i]);
-		strcat(symb, "/");
-		if(strcmp(symb, "./") == 0)
-			symb[0] = 0;
-		strcat(symb, str);
+		c = snprint(symb, NSYMB, "%s/%s", include[i], str)+1;
+		if(strncmp(symb, "./", 2) == 0){
+			c -= 2;
+			memmove(symb, symb+2, c);
+		}
 		f = open(symb, 0);
 		if(f >= 0)
 			break;
 	}
 	if(f < 0)
-		strcpy(symb, str);
-	c = strlen(symb) + 1;
+		c = snprint(symb, NSYMB, "%s", str)+1;
 	while(c & 3)
 		c++;
 	while(nhunk < c)
 		gethunk();
 	hp = hunk;
-	memcpy(hunk, symb, c);
+	memmove(hunk, symb, c);
 	nhunk -= c;
 	hunk += c;
 	newio();
--- a/sys/src/cmd/ka/a.h
+++ b/sys/src/cmd/ka/a.h
@@ -136,7 +136,7 @@
 void	domacro(void);
 void	macund(void);
 void	macdef(void);
-void	macexpand(Sym*, char*);
+void	macexpand(Sym*, char*, int);
 void	macinc(void);
 void	macprag(void);
 void	maclin(void);
--- a/sys/src/cmd/ka/lex.c
+++ b/sys/src/cmd/ka/lex.c
@@ -38,7 +38,7 @@
 		break;
 	} ARGEND
 	if(*argv == 0) {
-		print("usage: %ca [-options] file.s\n", thechar);
+		print("usage: %Ca [-options] file.s\n", thechar);
 		errorexit();
 	}
 	if(argc > 1 && systemtype(Windows)){
@@ -92,10 +92,10 @@
 int
 assemble(char *file)
 {
-	char ofile[100], incfile[20], *p;
+	char *ofile, *p;
 	int i, of;
 
-	strcpy(ofile, file);
+	ofile = strdup(file);
 	p = utfrrune(ofile, pathchar());
 	if(p) {
 		include[0] = ofile;
@@ -103,16 +103,13 @@
 	} else
 		p = ofile;
 	if(outfile == 0) {
-		outfile = p;
-		if(outfile){
+		if(p){
+			outfile = p;
 			p = utfrrune(outfile, '.');
 			if(p)
 				if(p[1] == 's' && p[2] == 0)
 					p[0] = 0;
-			p = utfrune(outfile, 0);
-			p[0] = '.';
-			p[1] = thechar;
-			p[2] = 0;
+			outfile = smprint("%s.%C", outfile, thechar);
 		} else
 			outfile = "/dev/null";
 	}
@@ -120,15 +117,13 @@
 	if(p) {
 		setinclude(p);
 	} else {
-		if(systemtype(Plan9)) {
-			sprint(incfile,"/%s/include", thestring);
-			setinclude(strdup(incfile));
-		}
+		if(systemtype(Plan9))
+			setinclude(smprint("/%s/include", thestring));
 	}
 
 	of = mycreat(outfile, 0664);
 	if(of < 0) {
-		yyerror("%ca: cannot create %s", thechar, outfile);
+		yyerror("%Ca: cannot create %s", thechar, outfile);
 		errorexit();
 	}
 	Binit(&obuf, of, OWRITE);
--- a/sys/src/cmd/kc/bits.c
+++ /dev/null
@@ -1,127 +1,0 @@
-#define	EXTERN
-#include "gc.h"
-
-/*
-Bits
-bor(Bits a, Bits b)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = a.b[i] | b.b[i];
-	return c;
-}
-*/
-
-/*
-Bits
-band(Bits a, Bits b)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = a.b[i] & b.b[i];
-	return c;
-}
-*/
-
-/*
-Bits
-bnot(Bits a)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = ~a.b[i];
-	return c;
-}
-*/
-
-int
-bany(Bits *a)
-{
-	int i;
-
-	for(i=0; i<BITS; i++)
-		if(a->b[i])
-			return 1;
-	return 0;
-}
-
-/*
-int
-beq(Bits a, Bits b)
-{
-	int i;
-
-	for(i=0; i<BITS; i++)
-		if(a.b[i] != b.b[i])
-			return 0;
-	return 1;
-}
-*/
-
-int
-bnum(Bits a)
-{
-	int i;
-	long b;
-
-	for(i=0; i<BITS; i++)
-		if(b = a.b[i])
-			return 32*i + bitno(b);
-	diag(Z, "bad in bnum");
-	return 0;
-}
-
-Bits
-blsh(unsigned n)
-{
-	Bits c;
-
-	c = zbits;
-	c.b[n/32] = 1L << (n%32);
-	return c;
-}
-
-/*
-int
-bset(Bits a, unsigned n)
-{
-	int i;
-
-	if(a.b[n/32] & (1L << (n%32)))
-		return 1;
-	return 0;
-}
-*/
-
-int
-Bconv(va_list *arg, Fconv *fp)
-{
-	char str[STRINGSZ], ss[STRINGSZ], *s;
-	Bits bits;
-	int i;
-
-	str[0] = 0;
-	bits = va_arg(*arg, Bits);
-	while(bany(&bits)) {
-		i = bnum(bits);
-		if(str[0])
-			strcat(str, " ");
-		if(var[i].sym == S) {
-			sprint(ss, "$%ld", var[i].offset);
-			s = ss;
-		} else
-			s = var[i].sym->name;
-		if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
-			break;
-		strcat(str, s);
-		bits.b[i/32] &= ~(1L << (i%32));
-	}
-	strconv(str, fp);
-	return 0;
-}
--- a/sys/src/cmd/kc/mul.c
+++ b/sys/src/cmd/kc/mul.c
@@ -117,8 +117,7 @@
 	if(g) {
 		m1 = mulcon0(n, v);
 		if(m1) {
-			strcpy(m->code, m1->code);
-			sprint(strchr(m->code, 0), "%c0", g+'a');
+			snprint(m->code, sizeof(m->code), "%s%c0", m1->code, g+'a');
 			return m;
 		}
 	}
--- a/sys/src/cmd/qa/a.h
+++ b/sys/src/cmd/qa/a.h
@@ -138,7 +138,7 @@
 void	domacro(void);
 void	macund(void);
 void	macdef(void);
-void	macexpand(Sym*, char*);
+void	macexpand(Sym*, char*, int);
 void	macinc(void);
 void	macprag(void);
 void	maclin(void);
--- a/sys/src/cmd/qa/lex.c
+++ b/sys/src/cmd/qa/lex.c
@@ -38,7 +38,7 @@
 		break;
 	} ARGEND
 	if(*argv == 0) {
-		print("usage: %ca [-options] file.s\n", thechar);
+		print("usage: %Ca [-options] file.s\n", thechar);
 		errorexit();
 	}
 	if(argc > 1 && systemtype(Windows)){
@@ -92,38 +92,38 @@
 int
 assemble(char *file)
 {
-	char ofile[100], incfile[20], *p;
+	char *ofile, *p;
 	int i, of;
 
-	strcpy(ofile, file);
-	if(p = strrchr(ofile, pathchar())) {
+	ofile = strdup(file);
+	p = utfrrune(ofile, pathchar());
+	if(p) {
 		include[0] = ofile;
 		*p++ = 0;
 	} else
 		p = ofile;
 	if(outfile == 0) {
-		outfile = p;
-		if(p = strrchr(outfile, '.'))
-			if(p[1] == 's' && p[2] == 0)
-				p[0] = 0;
-		p = strrchr(outfile, 0);
-		p[0] = '.';
-		p[1] = thechar;
-		p[2] = 0;
+		if(p){
+			outfile = p;
+			p = utfrrune(outfile, '.');
+			if(p)
+				if(p[1] == 's' && p[2] == 0)
+					p[0] = 0;
+			outfile = smprint("%s.%C", outfile, thechar);
+		} else
+			outfile = "/dev/null";
 	}
 	p = getenv("INCLUDE");
 	if(p) {
 		setinclude(p);
 	} else {
-		if(systemtype(Plan9)) {
-			sprint(incfile,"/%s/include", thestring);
-			setinclude(strdup(incfile));
-		}
+		if(systemtype(Plan9))
+			setinclude(smprint("/%s/include", thestring));
 	}
 
 	of = mycreat(outfile, 0664);
 	if(of < 0) {
-		yyerror("%ca: cannot create %s", thechar, outfile);
+		yyerror("%Ca: cannot create %s", thechar, outfile);
 		errorexit();
 	}
 	Binit(&obuf, of, OWRITE);
--- a/sys/src/cmd/qc/mul.c
+++ b/sys/src/cmd/qc/mul.c
@@ -117,8 +117,7 @@
 	if(g) {
 		m1 = mulcon0(n, v);
 		if(m1) {
-			strcpy(m->code, m1->code);
-			sprint(strchr(m->code, 0), "%c0", g+'a');
+			snprint(m->code, sizeof(m->code), "%s%c0", m1->code, g+'a');
 			return m;
 		}
 	}
--- a/sys/src/cmd/va/a.h
+++ b/sys/src/cmd/va/a.h
@@ -136,7 +136,7 @@
 void	domacro(void);
 void	macund(void);
 void	macdef(void);
-void	macexpand(Sym*, char*);
+void	macexpand(Sym*, char*, int);
 void	macinc(void);
 void	maclin(void);
 void	macprag(void);
--- a/sys/src/cmd/va/lex.c
+++ b/sys/src/cmd/va/lex.c
@@ -42,7 +42,7 @@
 		break;
 	} ARGEND
 	if(*argv == 0) {
-		print("usage: %ca [-options] file.s\n", thechar);
+		print("usage: %Ca [-options] file.s\n", thechar);
 		errorexit();
 	}
 	if(argc > 1 && systemtype(Windows)){
@@ -96,10 +96,10 @@
 int
 assemble(char *file)
 {
-	char ofile[100], incfile[20], *p;
+	char *ofile, *p;
 	int i, of;
 
-	strcpy(ofile, file);
+	ofile = strdup(file);
 	p = utfrrune(ofile, pathchar());
 	if(p) {
 		include[0] = ofile;
@@ -107,16 +107,13 @@
 	} else
 		p = ofile;
 	if(outfile == 0) {
-		outfile = p;
-		if(outfile){
+		if(p){
+			outfile = p;
 			p = utfrrune(outfile, '.');
 			if(p)
 				if(p[1] == 's' && p[2] == 0)
 					p[0] = 0;
-			p = utfrune(outfile, 0);
-			p[0] = '.';
-			p[1] = thechar;
-			p[2] = 0;
+			outfile = smprint("%s.%C", outfile, thechar);
 		} else
 			outfile = "/dev/null";
 	}
@@ -124,15 +121,13 @@
 	if(p) {
 		setinclude(p);
 	} else {
-		if(systemtype(Plan9)) {
-			sprint(incfile,"/%s/include", thestring);
-			setinclude(strdup(incfile));
-		}
+		if(systemtype(Plan9))
+			setinclude(smprint("/%s/include", thestring));
 	}
 
 	of = mycreat(outfile, 0664);
 	if(of < 0) {
-		yyerror("%ca: cannot create %s", thechar, outfile);
+		yyerror("%Ca: cannot create %s", thechar, outfile);
 		errorexit();
 	}
 	Binit(&obuf, of, OWRITE);