xref: /plan9-contrib/sys/src/ape/cmd/cc.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier #include <u.h>
2*219b2ee8SDavid du Colombier #include <libc.h>
3*219b2ee8SDavid du Colombier 
4*219b2ee8SDavid du Colombier /*
5*219b2ee8SDavid du Colombier    POSIX standard c89
6*219b2ee8SDavid du Colombier 
7*219b2ee8SDavid du Colombier    standard options: -c, -D name[=val], -E (preprocess to stdout),
8*219b2ee8SDavid du Colombier        -g, -L dir, -o outfile, -O, -s, -U name
9*219b2ee8SDavid du Colombier        (and operands can have -l lib interspersed)
10*219b2ee8SDavid du Colombier 
11*219b2ee8SDavid du Colombier     nonstandard but specified options: -S (assembly language left in .s),
12*219b2ee8SDavid du Colombier        -Wx,arg1[,arg2...] (pass arg(s) to phase x, where x is p (cpp)
13*219b2ee8SDavid du Colombier    			 0 (compiler), or l (loader)
14*219b2ee8SDavid du Colombier     nonstandard options: -v (echo real commands to stdout as they execute)
15*219b2ee8SDavid du Colombier 	-A: turn on ANSI prototype warnings
16*219b2ee8SDavid du Colombier  */
17*219b2ee8SDavid du Colombier 
18*219b2ee8SDavid du Colombier typedef struct Objtype {
19*219b2ee8SDavid du Colombier 	char	*name;
20*219b2ee8SDavid du Colombier 	char	*cc;
21*219b2ee8SDavid du Colombier 	char	*ld;
22*219b2ee8SDavid du Colombier 	char	*o;
23*219b2ee8SDavid du Colombier } Objtype;
24*219b2ee8SDavid du Colombier 
25*219b2ee8SDavid du Colombier Objtype objtype[] = {
26*219b2ee8SDavid du Colombier 	{"mips",	"vc", "vl", "v"},
27*219b2ee8SDavid du Colombier 	{"68020",	"2c", "2l", "2"},
28*219b2ee8SDavid du Colombier 	{"sparc",	"kc", "kl", "k"},
29*219b2ee8SDavid du Colombier 	{"386",		"8c", "8l", "8"},
30*219b2ee8SDavid du Colombier 	{"hobbit",	"zc", "zl", "z"},
31*219b2ee8SDavid du Colombier };
32*219b2ee8SDavid du Colombier 
33*219b2ee8SDavid du Colombier enum {
34*219b2ee8SDavid du Colombier 	Nobjs = (sizeof objtype)/(sizeof objtype[0]),
35*219b2ee8SDavid du Colombier 	Maxlist = 500,
36*219b2ee8SDavid du Colombier };
37*219b2ee8SDavid du Colombier 
38*219b2ee8SDavid du Colombier typedef struct List {
39*219b2ee8SDavid du Colombier 	char	*strings[Maxlist];
40*219b2ee8SDavid du Colombier 	int	n;
41*219b2ee8SDavid du Colombier } List;
42*219b2ee8SDavid du Colombier 
43*219b2ee8SDavid du Colombier List	srcs, objs, cpp, cc, ld, ldargs;
44*219b2ee8SDavid du Colombier int	cflag, vflag, Eflag, Sflag, Aflag;
45*219b2ee8SDavid du Colombier char	*allos = "28kvz";
46*219b2ee8SDavid du Colombier 
47*219b2ee8SDavid du Colombier void	append(List *, char *);
48*219b2ee8SDavid du Colombier char	*changeext(char *, char *);
49*219b2ee8SDavid du Colombier void	doexec(char *, List *);
50*219b2ee8SDavid du Colombier void	dopipe(char *, List *, char *, List *);
51*219b2ee8SDavid du Colombier void	fatal(char *);
52*219b2ee8SDavid du Colombier Objtype	*findoty(void);
53*219b2ee8SDavid du Colombier void	printlist(List *);
54*219b2ee8SDavid du Colombier char	*str(char *, ...);
55*219b2ee8SDavid du Colombier char *searchlib(char *, char*);
56*219b2ee8SDavid du Colombier 
57*219b2ee8SDavid du Colombier void
58*219b2ee8SDavid du Colombier main(int argc, char *argv[])
59*219b2ee8SDavid du Colombier {
60*219b2ee8SDavid du Colombier 	char *s, *suf, *ccpath, *lib;
61*219b2ee8SDavid du Colombier 	char *oname;
62*219b2ee8SDavid du Colombier 	int i, cppn, ccn;
63*219b2ee8SDavid du Colombier 	Objtype *ot;
64*219b2ee8SDavid du Colombier 
65*219b2ee8SDavid du Colombier 	ot = findoty();
66*219b2ee8SDavid du Colombier 	oname = "a.out";
67*219b2ee8SDavid du Colombier 	append(&cpp, "cpp");
68*219b2ee8SDavid du Colombier 	append(&cpp, "-D__STDC__=1");	/* ANSI says so */
69*219b2ee8SDavid du Colombier 	append(&cpp, "-D_POSIX_SOURCE=");
70*219b2ee8SDavid du Colombier 	append(&cpp, "-N");		/* turn off standard includes */
71*219b2ee8SDavid du Colombier 	append(&cc, ot->cc);
72*219b2ee8SDavid du Colombier 	append(&cc, "-J");		/* old/new decl mixture hack */
73*219b2ee8SDavid du Colombier 	append(&ld, ot->ld);
74*219b2ee8SDavid du Colombier 	while(argc > 0) {
75*219b2ee8SDavid du Colombier 		ARGBEGIN {
76*219b2ee8SDavid du Colombier 		case 'c':
77*219b2ee8SDavid du Colombier 			cflag = 1;
78*219b2ee8SDavid du Colombier 			break;
79*219b2ee8SDavid du Colombier 		case 'l':
80*219b2ee8SDavid du Colombier 			lib = searchlib(ARGF(), ot->name);
81*219b2ee8SDavid du Colombier 			if(!lib)
82*219b2ee8SDavid du Colombier 				fprint(2, "cc: can't find library for -l\n");
83*219b2ee8SDavid du Colombier 			else
84*219b2ee8SDavid du Colombier 				append(&objs, lib);
85*219b2ee8SDavid du Colombier 			break;
86*219b2ee8SDavid du Colombier 		case 'o':
87*219b2ee8SDavid du Colombier 			oname = ARGF();
88*219b2ee8SDavid du Colombier 			if(!oname)
89*219b2ee8SDavid du Colombier 				fatal("cc: no -o argument");
90*219b2ee8SDavid du Colombier 			break;
91*219b2ee8SDavid du Colombier 		case 'D':
92*219b2ee8SDavid du Colombier 		case 'I':
93*219b2ee8SDavid du Colombier 		case 'U':
94*219b2ee8SDavid du Colombier 			append(&cpp, str("-%c%s", ARGC(), ARGF()));
95*219b2ee8SDavid du Colombier 			break;
96*219b2ee8SDavid du Colombier 		case 'E':
97*219b2ee8SDavid du Colombier 			Eflag = 1;
98*219b2ee8SDavid du Colombier 			cflag = 1;
99*219b2ee8SDavid du Colombier 			break;
100*219b2ee8SDavid du Colombier 		case 's':
101*219b2ee8SDavid du Colombier 		case 'g':
102*219b2ee8SDavid du Colombier 		case 'O':
103*219b2ee8SDavid du Colombier 			break;
104*219b2ee8SDavid du Colombier 		case 'W':
105*219b2ee8SDavid du Colombier 			s = ARGF();
106*219b2ee8SDavid du Colombier 			if(s && s[1]==',') {
107*219b2ee8SDavid du Colombier 				switch (s[0]) {
108*219b2ee8SDavid du Colombier 				case 'p':
109*219b2ee8SDavid du Colombier 					append(&cpp, s+2);
110*219b2ee8SDavid du Colombier 					break;
111*219b2ee8SDavid du Colombier 				case '0':
112*219b2ee8SDavid du Colombier 					append(&cc, s+2);
113*219b2ee8SDavid du Colombier 					break;
114*219b2ee8SDavid du Colombier 				case 'l':
115*219b2ee8SDavid du Colombier 					append(&ldargs, s+2);
116*219b2ee8SDavid du Colombier 					break;
117*219b2ee8SDavid du Colombier 				default:
118*219b2ee8SDavid du Colombier 					fprint(2, "cc: pass letter after -W should be one of p0l; ignored\n");
119*219b2ee8SDavid du Colombier 				}
120*219b2ee8SDavid du Colombier 			} else
121*219b2ee8SDavid du Colombier 				fprint(2, "cc: bad option after -W; ignored\n");
122*219b2ee8SDavid du Colombier 			break;
123*219b2ee8SDavid du Colombier 		case 'v':
124*219b2ee8SDavid du Colombier 			vflag = 1;
125*219b2ee8SDavid du Colombier 			append(&ldargs, "-v");
126*219b2ee8SDavid du Colombier 			break;
127*219b2ee8SDavid du Colombier 		case 'A':
128*219b2ee8SDavid du Colombier 			Aflag = 1;
129*219b2ee8SDavid du Colombier 			break;
130*219b2ee8SDavid du Colombier 		case 'S':
131*219b2ee8SDavid du Colombier 			Sflag = 1;
132*219b2ee8SDavid du Colombier 			break;
133*219b2ee8SDavid du Colombier 		default:
134*219b2ee8SDavid du Colombier 			fprint(2, "cc: flag -%c ignored\n", ARGC());
135*219b2ee8SDavid du Colombier 			break;
136*219b2ee8SDavid du Colombier 		} ARGEND
137*219b2ee8SDavid du Colombier 		if(!Aflag)
138*219b2ee8SDavid du Colombier 			append(&cc, "-B");		/* turn off non-prototype warnings */
139*219b2ee8SDavid du Colombier 		if(argc > 0) {
140*219b2ee8SDavid du Colombier 			s = argv[0];
141*219b2ee8SDavid du Colombier 			suf = utfrrune(s, '.');
142*219b2ee8SDavid du Colombier 			if(suf) {
143*219b2ee8SDavid du Colombier 				suf++;
144*219b2ee8SDavid du Colombier 				if(strcmp(suf, "c") == 0) {
145*219b2ee8SDavid du Colombier 					append(&srcs, s);
146*219b2ee8SDavid du Colombier 					append(&objs, changeext(s, "o"));
147*219b2ee8SDavid du Colombier 				} else if(strcmp(suf, "o") == 0 ||
148*219b2ee8SDavid du Colombier 					  strcmp(suf, ot->o) == 0 ||
149*219b2ee8SDavid du Colombier 					  strcmp(suf, "a") == 0 ||
150*219b2ee8SDavid du Colombier 					  (suf[0] == 'a' && strcmp(suf+1, ot->o) == 0)) {
151*219b2ee8SDavid du Colombier 					append(&objs, s);
152*219b2ee8SDavid du Colombier 				} else if(utfrune(allos, suf[0]) != 0) {
153*219b2ee8SDavid du Colombier 					fprint(2, "cc: argument %s ignored: wrong architecture\n",
154*219b2ee8SDavid du Colombier 						s);
155*219b2ee8SDavid du Colombier 				}
156*219b2ee8SDavid du Colombier 			}
157*219b2ee8SDavid du Colombier 		}
158*219b2ee8SDavid du Colombier 	}
159*219b2ee8SDavid du Colombier 	if(objs.n == 0)
160*219b2ee8SDavid du Colombier 		fatal("no files to compile or load");
161*219b2ee8SDavid du Colombier 	ccpath = str("/bin/%s", ot->cc);
162*219b2ee8SDavid du Colombier 	append(&cpp, str("-I/%s/include/ape", ot->name));
163*219b2ee8SDavid du Colombier 	append(&cpp, "-I/sys/include/ape");
164*219b2ee8SDavid du Colombier 	cppn = cpp.n;
165*219b2ee8SDavid du Colombier 	ccn = cc.n;
166*219b2ee8SDavid du Colombier 	for(i = 0; i < srcs.n; i++) {
167*219b2ee8SDavid du Colombier 		append(&cpp, srcs.strings[i]);
168*219b2ee8SDavid du Colombier 		if(Eflag)
169*219b2ee8SDavid du Colombier 			doexec("/bin/cpp", &cpp);
170*219b2ee8SDavid du Colombier 		else {
171*219b2ee8SDavid du Colombier 			if(Sflag)
172*219b2ee8SDavid du Colombier 				append(&cc, "-S");
173*219b2ee8SDavid du Colombier 			else {
174*219b2ee8SDavid du Colombier 				append(&cc, "-o");
175*219b2ee8SDavid du Colombier 				append(&cc, changeext(objs.strings[i], "o"));
176*219b2ee8SDavid du Colombier 			}
177*219b2ee8SDavid du Colombier 			dopipe("/bin/cpp", &cpp, ccpath, &cc);
178*219b2ee8SDavid du Colombier 		}
179*219b2ee8SDavid du Colombier 		cpp.n = cppn;
180*219b2ee8SDavid du Colombier 		cc.n = ccn;
181*219b2ee8SDavid du Colombier 	}
182*219b2ee8SDavid du Colombier 	if(!cflag) {
183*219b2ee8SDavid du Colombier 		append(&ld, "-o");
184*219b2ee8SDavid du Colombier 		append(&ld, oname);
185*219b2ee8SDavid du Colombier 		for(i = 0; i < ldargs.n; i++)
186*219b2ee8SDavid du Colombier 			append(&ld, ldargs.strings[i]);
187*219b2ee8SDavid du Colombier 		for(i = 0; i < objs.n; i++)
188*219b2ee8SDavid du Colombier 			append(&ld, objs.strings[i]);
189*219b2ee8SDavid du Colombier 		doexec(str("/bin/%s", ot->ld), &ld);
190*219b2ee8SDavid du Colombier 		if(objs.n == 1)
191*219b2ee8SDavid du Colombier 			remove(objs.strings[0]);
192*219b2ee8SDavid du Colombier 	}
193*219b2ee8SDavid du Colombier 
194*219b2ee8SDavid du Colombier 	exits(0);
195*219b2ee8SDavid du Colombier }
196*219b2ee8SDavid du Colombier 
197*219b2ee8SDavid du Colombier char *
198*219b2ee8SDavid du Colombier searchlib(char *s, char *objtype)
199*219b2ee8SDavid du Colombier {
200*219b2ee8SDavid du Colombier 	char *l;
201*219b2ee8SDavid du Colombier 	if(!s)
202*219b2ee8SDavid du Colombier 		return 0;
203*219b2ee8SDavid du Colombier 	switch(s[0]) {
204*219b2ee8SDavid du Colombier 	case 'c':
205*219b2ee8SDavid du Colombier 		l = str("/%s/lib/ape/libap.a", objtype);
206*219b2ee8SDavid du Colombier 		break;
207*219b2ee8SDavid du Colombier 	case 'm':
208*219b2ee8SDavid du Colombier 		l = str("/%s/lib/ape/libap.a", objtype);
209*219b2ee8SDavid du Colombier 		break;
210*219b2ee8SDavid du Colombier 	case 'l':
211*219b2ee8SDavid du Colombier 		l = str("/%s/lib/ape/libl.a", objtype);
212*219b2ee8SDavid du Colombier 		break;
213*219b2ee8SDavid du Colombier 	case 'y':
214*219b2ee8SDavid du Colombier 		l = str("/%s/lib/ape/liby.a", objtype);
215*219b2ee8SDavid du Colombier 		break;
216*219b2ee8SDavid du Colombier 	default:
217*219b2ee8SDavid du Colombier 		l = str("/%s/lib/ape/lib%s.a", objtype, s);
218*219b2ee8SDavid du Colombier 	}
219*219b2ee8SDavid du Colombier 	return l;
220*219b2ee8SDavid du Colombier }
221*219b2ee8SDavid du Colombier 
222*219b2ee8SDavid du Colombier void
223*219b2ee8SDavid du Colombier append(List *l, char *s)
224*219b2ee8SDavid du Colombier {
225*219b2ee8SDavid du Colombier 	if(l->n >= Maxlist-1)
226*219b2ee8SDavid du Colombier 		fatal("too many arguments");
227*219b2ee8SDavid du Colombier 	l->strings[l->n++] = s;
228*219b2ee8SDavid du Colombier 	l->strings[l->n] = 0;
229*219b2ee8SDavid du Colombier }
230*219b2ee8SDavid du Colombier 
231*219b2ee8SDavid du Colombier void
232*219b2ee8SDavid du Colombier doexec(char *c, List *a)
233*219b2ee8SDavid du Colombier {
234*219b2ee8SDavid du Colombier 	Waitmsg w;
235*219b2ee8SDavid du Colombier 	int pid;
236*219b2ee8SDavid du Colombier 
237*219b2ee8SDavid du Colombier 	if(vflag) {
238*219b2ee8SDavid du Colombier 		printlist(a);
239*219b2ee8SDavid du Colombier 		fprint(2, "\n");
240*219b2ee8SDavid du Colombier 	}
241*219b2ee8SDavid du Colombier 	switch(fork()) {
242*219b2ee8SDavid du Colombier 	case -1:
243*219b2ee8SDavid du Colombier 		fatal("fork failed");
244*219b2ee8SDavid du Colombier 	case 0:
245*219b2ee8SDavid du Colombier 		exec(c, a->strings);
246*219b2ee8SDavid du Colombier 		fatal("exec failed");
247*219b2ee8SDavid du Colombier 	}
248*219b2ee8SDavid du Colombier 	pid = wait(&w);
249*219b2ee8SDavid du Colombier 	if(pid < 0)
250*219b2ee8SDavid du Colombier 		fatal("wait failed");
251*219b2ee8SDavid du Colombier 	if(w.msg[0])
252*219b2ee8SDavid du Colombier 		fatal(str("%s: %s", a->strings[0], w.msg));
253*219b2ee8SDavid du Colombier }
254*219b2ee8SDavid du Colombier 
255*219b2ee8SDavid du Colombier void
256*219b2ee8SDavid du Colombier dopipe(char *c1, List *a1, char *c2, List *a2)
257*219b2ee8SDavid du Colombier {
258*219b2ee8SDavid du Colombier 	Waitmsg w;
259*219b2ee8SDavid du Colombier 	int pid, pid1, got;
260*219b2ee8SDavid du Colombier 	int fd[2];
261*219b2ee8SDavid du Colombier 
262*219b2ee8SDavid du Colombier 	if(vflag) {
263*219b2ee8SDavid du Colombier 		printlist(a1);
264*219b2ee8SDavid du Colombier 		fprint(2, " | ");
265*219b2ee8SDavid du Colombier 		printlist(a2);
266*219b2ee8SDavid du Colombier 		fprint(2, "\n");
267*219b2ee8SDavid du Colombier 	}
268*219b2ee8SDavid du Colombier 	if(pipe(fd) < 0)
269*219b2ee8SDavid du Colombier 		fatal("pipe failed");
270*219b2ee8SDavid du Colombier 	switch((pid1 = fork())) {
271*219b2ee8SDavid du Colombier 	case -1:
272*219b2ee8SDavid du Colombier 		fatal("fork failed");
273*219b2ee8SDavid du Colombier 	case 0:
274*219b2ee8SDavid du Colombier 		dup(fd[0], 0);
275*219b2ee8SDavid du Colombier 		close(fd[0]);
276*219b2ee8SDavid du Colombier 		close(fd[1]);
277*219b2ee8SDavid du Colombier 		exec(c2, a2->strings);
278*219b2ee8SDavid du Colombier 		fatal("exec failed");
279*219b2ee8SDavid du Colombier 	}
280*219b2ee8SDavid du Colombier 	switch(fork()) {
281*219b2ee8SDavid du Colombier 	case -1:
282*219b2ee8SDavid du Colombier 		fatal("fork failed");
283*219b2ee8SDavid du Colombier 	case 0:
284*219b2ee8SDavid du Colombier 		close(0);
285*219b2ee8SDavid du Colombier 		dup(fd[1], 1);
286*219b2ee8SDavid du Colombier 		close(fd[0]);
287*219b2ee8SDavid du Colombier 		close(fd[1]);
288*219b2ee8SDavid du Colombier 		exec(c1, a1->strings);
289*219b2ee8SDavid du Colombier 		fatal("exec failed");
290*219b2ee8SDavid du Colombier 	}
291*219b2ee8SDavid du Colombier 	close(fd[0]);
292*219b2ee8SDavid du Colombier 	close(fd[1]);
293*219b2ee8SDavid du Colombier 	for(got = 0; got < 2; got++) {
294*219b2ee8SDavid du Colombier 		pid = wait(&w);
295*219b2ee8SDavid du Colombier 		if(pid < 0)
296*219b2ee8SDavid du Colombier 			fatal("wait failed");
297*219b2ee8SDavid du Colombier 		if(w.msg[0])
298*219b2ee8SDavid du Colombier 			fatal(str("%s: %s",
299*219b2ee8SDavid du Colombier 			   (pid == pid1) ? a1->strings[0] : a2->strings[0], w.msg));
300*219b2ee8SDavid du Colombier 	}
301*219b2ee8SDavid du Colombier }
302*219b2ee8SDavid du Colombier 
303*219b2ee8SDavid du Colombier Objtype *
304*219b2ee8SDavid du Colombier findoty(void)
305*219b2ee8SDavid du Colombier {
306*219b2ee8SDavid du Colombier 	char *o;
307*219b2ee8SDavid du Colombier 	Objtype *oty;
308*219b2ee8SDavid du Colombier 
309*219b2ee8SDavid du Colombier 	o = getenv("objtype");
310*219b2ee8SDavid du Colombier 	if(!o)
311*219b2ee8SDavid du Colombier 		fatal("no $objtype in environment");
312*219b2ee8SDavid du Colombier 	for(oty = objtype; oty < &objtype[Nobjs]; oty++)
313*219b2ee8SDavid du Colombier 		if(strcmp(o, oty->name) == 0)
314*219b2ee8SDavid du Colombier 			return oty;
315*219b2ee8SDavid du Colombier 	fatal("unknown $objtype");
316*219b2ee8SDavid du Colombier 	return 0;			/* shut compiler up */
317*219b2ee8SDavid du Colombier }
318*219b2ee8SDavid du Colombier 
319*219b2ee8SDavid du Colombier void
320*219b2ee8SDavid du Colombier fatal(char *msg)
321*219b2ee8SDavid du Colombier {
322*219b2ee8SDavid du Colombier 	fprint(2, "cc: %s\n", msg);
323*219b2ee8SDavid du Colombier 	exits(msg);
324*219b2ee8SDavid du Colombier }
325*219b2ee8SDavid du Colombier 
326*219b2ee8SDavid du Colombier /* src ends in .something; return copy of basename with .ext added */
327*219b2ee8SDavid du Colombier char *
328*219b2ee8SDavid du Colombier changeext(char *src, char *ext)
329*219b2ee8SDavid du Colombier {
330*219b2ee8SDavid du Colombier 	char *b, *e, *ans;
331*219b2ee8SDavid du Colombier 
332*219b2ee8SDavid du Colombier 	b = utfrrune(src, '/');
333*219b2ee8SDavid du Colombier 	if(b)
334*219b2ee8SDavid du Colombier 		b++;
335*219b2ee8SDavid du Colombier 	else
336*219b2ee8SDavid du Colombier 		b = src;
337*219b2ee8SDavid du Colombier 	e = utfrrune(src, '.');
338*219b2ee8SDavid du Colombier 	if(!e)
339*219b2ee8SDavid du Colombier 		return 0;
340*219b2ee8SDavid du Colombier 	*e = 0;
341*219b2ee8SDavid du Colombier 	ans = str("%s.%s", b, ext);
342*219b2ee8SDavid du Colombier 	*e = '.';
343*219b2ee8SDavid du Colombier 	return ans;
344*219b2ee8SDavid du Colombier }
345*219b2ee8SDavid du Colombier 
346*219b2ee8SDavid du Colombier void
347*219b2ee8SDavid du Colombier printlist(List *l)
348*219b2ee8SDavid du Colombier {
349*219b2ee8SDavid du Colombier 	int i;
350*219b2ee8SDavid du Colombier 
351*219b2ee8SDavid du Colombier 	for(i = 0; i < l->n; i++) {
352*219b2ee8SDavid du Colombier 		fprint(2, "%s", l->strings[i]);
353*219b2ee8SDavid du Colombier 		if(i < l->n - 1)
354*219b2ee8SDavid du Colombier 			fprint(2, " ");
355*219b2ee8SDavid du Colombier 	}
356*219b2ee8SDavid du Colombier }
357*219b2ee8SDavid du Colombier 
358*219b2ee8SDavid du Colombier char *
359*219b2ee8SDavid du Colombier str(char *fmt, ...)
360*219b2ee8SDavid du Colombier {
361*219b2ee8SDavid du Colombier 	char *s;
362*219b2ee8SDavid du Colombier 	char buf[1000];
363*219b2ee8SDavid du Colombier 
364*219b2ee8SDavid du Colombier 	doprint(buf, &buf[sizeof buf], fmt, ((long *)&fmt)+1);
365*219b2ee8SDavid du Colombier 	s = malloc(strlen(buf)+1);
366*219b2ee8SDavid du Colombier 	strcpy(s, buf);
367*219b2ee8SDavid du Colombier 	return s;
368*219b2ee8SDavid du Colombier }
369