* Changed many files to use mkvalue() instead of newtupleobject().
* Fixcprt.py: added [-y file] option, do only files younger than file.
* modsupport.[ch]: added vmkvalue().
* intobject.c: use mkvalue().
* stringobject.c: added "formatstring"; renamed string* to string_*;
  ceval.c: call formatstring for string % value.
* longobject.c: close memory leak in divmod.
* parsetok.c: set result node to NULL when returning an error.
diff --git a/Objects/stringobject.c b/Objects/stringobject.c
index 9f8de92..25f12fc 100644
--- a/Objects/stringobject.c
+++ b/Objects/stringobject.c
@@ -1,6 +1,6 @@
 /***********************************************************
-Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
-Netherlands.
+Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
+Amsterdam, The Netherlands.
 
                         All Rights Reserved
 
@@ -61,7 +61,7 @@
 }
 
 void
-stringdealloc(op)
+string_dealloc(op)
 	object *op;
 {
 	DEL(op);
@@ -92,7 +92,7 @@
 /* Methods */
 
 static int
-stringprint(op, fp, flags)
+string_print(op, fp, flags)
 	stringobject *op;
 	FILE *fp;
 	int flags;
@@ -119,7 +119,7 @@
 }
 
 static object *
-stringrepr(op)
+string_repr(op)
 	register stringobject *op;
 {
 	/* XXX overflow? */
@@ -155,14 +155,14 @@
 }
 
 static int
-stringlength(a)
+string_length(a)
 	stringobject *a;
 {
 	return a->ob_size;
 }
 
 static object *
-stringconcat(a, bb)
+string_concat(a, bb)
 	register stringobject *a;
 	register object *bb;
 {
@@ -198,7 +198,7 @@
 }
 
 static object *
-stringrepeat(a, n)
+string_repeat(a, n)
 	register stringobject *a;
 	register int n;
 {
@@ -228,7 +228,7 @@
 /* String slice a[i:j] consists of characters a[i] ... a[j-1] */
 
 static object *
-stringslice(a, i, j)
+string_slice(a, i, j)
 	register stringobject *a;
 	register int i, j; /* May be negative! */
 {
@@ -258,7 +258,7 @@
 static object *characters[UCHAR_MAX + 1];
 
 static object *
-stringitem(a, i)
+string_item(a, i)
 	stringobject *a;
 	register int i;
 {
@@ -282,7 +282,7 @@
 }
 
 static int
-stringcompare(a, b)
+string_compare(a, b)
 	stringobject *a, *b;
 {
 	int len_a = a->ob_size, len_b = b->ob_size;
@@ -294,11 +294,11 @@
 }
 
 static sequence_methods string_as_sequence = {
-	stringlength,	/*sq_length*/
-	stringconcat,	/*sq_concat*/
-	stringrepeat,	/*sq_repeat*/
-	stringitem,	/*sq_item*/
-	stringslice,	/*sq_slice*/
+	string_length,	/*sq_length*/
+	string_concat,	/*sq_concat*/
+	string_repeat,	/*sq_repeat*/
+	string_item,	/*sq_item*/
+	string_slice,	/*sq_slice*/
 	0,		/*sq_ass_item*/
 	0,		/*sq_ass_slice*/
 };
@@ -309,12 +309,12 @@
 	"string",
 	sizeof(stringobject),
 	sizeof(char),
-	stringdealloc,	/*tp_dealloc*/
-	stringprint,	/*tp_print*/
+	string_dealloc,	/*tp_dealloc*/
+	string_print,	/*tp_print*/
 	0,		/*tp_getattr*/
 	0,		/*tp_setattr*/
-	stringcompare,	/*tp_compare*/
-	stringrepr,	/*tp_repr*/
+	string_compare,	/*tp_compare*/
+	string_repr,	/*tp_repr*/
 	0,		/*tp_as_number*/
 	&string_as_sequence,	/*tp_as_sequence*/
 	0,		/*tp_as_mapping*/
@@ -328,7 +328,7 @@
 	register object *v;
 	if (*pv == NULL || w == NULL || !is_stringobject(*pv))
 		return;
-	v = stringconcat((stringobject *) *pv, w);
+	v = string_concat((stringobject *) *pv, w);
 	DECREF(*pv);
 	*pv = v;
 }
@@ -373,3 +373,344 @@
 	sv->ob_sval[newsize] = '\0';
 	return 0;
 }
+
+/* Helpers for formatstring */
+
+static object *
+getnextarg(args, arglen, p_argidx)
+	object *args;
+	int arglen;
+	int *p_argidx;
+{
+	int argidx = *p_argidx;
+	if (argidx < arglen) {
+		(*p_argidx)++;
+		if (arglen < 0)
+			return args;
+		else
+			return gettupleitem(args, argidx);
+	}
+	err_setstr(TypeError, "not enough arguments for format string");
+	return NULL;
+}
+
+#define F_LJUST (1<<0)
+#define F_SIGN	(1<<1)
+#define F_BLANK (1<<2)
+#define F_ALT	(1<<3)
+#define F_ZERO	(1<<4)
+
+extern double fabs PROTO((double));
+
+static char *
+formatfloat(flags, prec, type, v)
+	int flags;
+	int prec;
+	int type;
+	object *v;
+{
+	char fmt[20];
+	static char buf[120];
+	double x;
+	if (!getargs(v, "d;float argument required", &x))
+		return NULL;
+	if (prec < 0)
+		prec = 6;
+	if (prec > 50)
+		prec = 50; /* Arbitrary limitation */
+	if (type == 'f' && fabs(x)/1e25 >= 1e25)
+		type = 'g';
+	sprintf(fmt, "%%%s.%d%c", (flags&F_ALT) ? "#" : "", prec, type);
+	sprintf(buf, fmt, x);
+	return buf;
+}
+
+static char *
+formatint(flags, prec, type, v)
+	int flags;
+	int prec;
+	int type;
+	object *v;
+{
+	char fmt[20];
+	static char buf[50];
+	long x;
+	if (!getargs(v, "l;int argument required", &x))
+		return NULL;
+	if (prec < 0)
+		prec = 1;
+	sprintf(fmt, "%%%s.%dl%c", (flags&F_ALT) ? "#" : "", prec, type);
+	sprintf(buf, fmt, x);
+	return buf;
+}
+
+static char *
+formatchar(v)
+	object *v;
+{
+	static char buf[2];
+	if (is_stringobject(v)) {
+		if (!getargs(v, "c;%c requires int or char", &buf[0]))
+			return NULL;
+	}
+	else {
+		if (!getargs(v, "b;%c requires int or char", &buf[0]))
+			return NULL;
+	}
+	buf[1] = '\0';
+	return buf;
+}
+
+/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) */
+
+object *
+formatstring(format, args)
+	object *format;
+	object *args;
+{
+	char *fmt, *res;
+	int fmtcnt, rescnt, reslen, arglen, argidx;
+	object *result;
+	if (format == NULL || !is_stringobject(format) || args == NULL) {
+		err_badcall();
+		return NULL;
+	}
+	reslen = rescnt = 100;
+	result = newsizedstringobject((char *)NULL, reslen);
+	if (result == NULL)
+		return NULL;
+	res = getstringvalue(result);
+	fmt = getstringvalue(format);
+	fmtcnt = getstringsize(format);
+	if (is_tupleobject(args)) {
+		arglen = gettuplesize(args);
+		argidx = 0;
+	}
+	else {
+		arglen = -1;
+		argidx = -2;
+	}
+	while (--fmtcnt >= 0) {
+		if (*fmt != '%') {
+			if (--rescnt < 0) {
+				rescnt = reslen;
+				reslen = reslen * 2; /* Maybe less when big? */
+				if (resizestring(&result, reslen) < 0)
+					return NULL;
+				res = getstringvalue(result) + rescnt;
+				rescnt = reslen - rescnt;
+			}
+			*res++ = *fmt++;
+		}
+		else {
+			/* Got a format specifier */
+			int flags = 0;
+			char *fmtstart = fmt++;
+			int width = -1;
+			int prec = -1;
+			int size = 0;
+			int c;
+			int fill;
+			object *v;
+			char *buf;
+			int sign;
+			int len;
+			while (--fmtcnt >= 0) {
+				switch (c = *fmt++) {
+				case '-': flags |= F_LJUST; continue;
+				case '+': flags |= F_SIGN; continue;
+				case ' ': flags |= F_BLANK; continue;
+				case '#': flags |= F_ALT; continue;
+				case '0': flags |= F_ZERO; continue;
+				}
+				break;
+			}
+			if (c == '*') {
+				v = getnextarg(args, arglen, &argidx);
+				if (v == NULL)
+					goto error;
+				if (!is_intobject(v)) {
+					err_setstr(TypeError, "* wants int");
+					goto error;
+				}
+				width = getintvalue(v);
+				if (width < 0)
+					width = 0;
+				if (--fmtcnt >= 0)
+					c = *fmt++;
+			}
+			else if (isdigit(c)) {
+				width = c - '0';
+				while (--fmtcnt >= 0) {
+					c = *fmt++;
+					if (!isdigit(c))
+						break;
+					if ((width*10) / 10 != width) {
+						err_setstr(ValueError,
+							   "width too big");
+						goto error;
+					}
+					width = width*10 + (c - '0');
+				}
+			}
+			if (c == '.') {
+				prec = 0;
+				if (--fmtcnt >= 0)
+					c = *fmt++;
+				if (c == '*') {
+					v = getnextarg(args, arglen, &argidx);
+					if (v == NULL)
+						goto error;
+					if (!is_intobject(v)) {
+						err_setstr(TypeError,
+							   "* wants int");
+						goto error;
+					}
+					prec = getintvalue(v);
+					if (prec < 0)
+						prec = 0;
+					if (--fmtcnt >= 0)
+						c = *fmt++;
+				}
+				else if (isdigit(c)) {
+					prec = c - '0';
+					while (--fmtcnt >= 0) {
+						c = *fmt++;
+						if (!isdigit(c))
+							break;
+						if ((prec*10) / 10 != prec) {
+							err_setstr(ValueError,
+							    "prec too big");
+							goto error;
+						}
+						prec = prec*10 + (c - '0');
+					}
+				}
+			} /* prec */
+			if (fmtcnt >= 0) {
+				if (c == 'h' || c == 'l' || c == 'L') {
+					size = c;
+					if (--fmtcnt >= 0)
+						c = *fmt++;
+				}
+			}
+			if (fmtcnt < 0) {
+				err_setstr(ValueError, "incomplete format");
+				goto error;
+			}
+			if (c != '%') {
+				v = getnextarg(args, arglen, &argidx);
+				if (v == NULL)
+					goto error;
+			}
+			sign = 0;
+			fill = ' ';
+			switch (c) {
+			case '%':
+				buf = "%";
+				len = 1;
+				break;
+			case 's':
+				if (!is_stringobject(v)) {
+					err_setstr(TypeError,
+						   "%s wants string");
+					goto error;
+				}
+				buf = getstringvalue(v);
+				len = getstringsize(v);
+				if (prec >= 0 && len > prec)
+					len = prec;
+				break;
+			case 'i':
+			case 'd':
+			case 'u':
+			case 'o':
+			case 'x':
+			case 'X':
+				if (c == 'i')
+					c = 'd';
+				buf = formatint(flags, prec, c, v);
+				if (buf == NULL)
+					goto error;
+				len = strlen(buf);
+				sign = (c == 'd');
+				if (flags&F_ZERO)
+					fill = '0';
+				break;
+			case 'e':
+			case 'E':
+			case 'f':
+			case 'g':
+			case 'G':
+				buf = formatfloat(flags, prec, c, v);
+				if (buf == NULL)
+					goto error;
+				len = strlen(buf);
+				sign = 1;
+				if (flags&F_ZERO)
+					fill = '0';
+				break;
+			case 'c':
+				buf = formatchar(v);
+				if (buf == NULL)
+					goto error;
+				len = strlen(buf);
+				break;
+			default:
+				err_setstr(ValueError,
+					   "unsupported format character");
+				goto error;
+			}
+			if (sign) {
+				if (*buf == '-' || *buf == '+') {
+					sign = *buf++;
+					len--;
+				}
+				else if (flags & F_SIGN)
+					sign = '+';
+				else if (flags & F_BLANK)
+					sign = ' ';
+				else
+					sign = '\0';
+			}
+			if (width < len)
+				width = len;
+			if (rescnt < width + (sign != '\0')) {
+				rescnt = reslen;
+				reslen = reslen + width + 100;
+				if (resizestring(&result, reslen) < 0)
+					return NULL;
+				res = getstringvalue(result) + rescnt;
+				rescnt = reslen - rescnt;
+			}
+			if (sign) {
+				*res++ = sign;
+				rescnt--;
+				if (width > len)
+					width--;
+			}
+			if (width > len && !(flags&F_LJUST)) {
+				do {
+					--rescnt;
+					*res++ = fill;
+				} while (--width > len);
+			}
+			memcpy(res, buf, len);
+			res += len;
+			rescnt -= len;
+			while (--width >= len) {
+				--rescnt;
+				*res++ = ' ';
+			}
+		} /* '%' */
+	} /* until end */
+	if (argidx < arglen) {
+		err_setstr(TypeError, "not all arguments converted");
+		goto error;
+	}
+	resizestring(&result, reslen - rescnt);
+	return result;
+ error:
+	DECREF(result);
+	return NULL;
+}