[Python-checkins] CVS: python/dist/src/Objects stringobject.c,2.124,2.125

Barry Warsaw bwarsaw@users.sourceforge.net
Fri, 24 Aug 2001 11:32:08 -0700


Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv13719/Objects

Modified Files:
	stringobject.c 
Log Message:
PyString_FromFormat() and PyString_FromFormatV(): Largely ripped from
    PyErr_Format() these new C API methods can be used instead of
    sprintf()'s into hardcoded char* buffers.  This allows us to fix
    many situation where long package, module, or class names get
    truncated in reprs.

    PyString_FromFormat() is the varargs variety.
    PyString_FromFormatV() is the va_list variety

    Original PyErr_Format() code was modified to allow %p and %ld
    expansions.

    Many reprs were converted to this, checkins coming soo.  Not
    changed: complex_repr(), float_repr(), float_print(), float_str(),
    int_repr().  There may be other candidates not yet converted.

    Closes patch #454743.


Index: stringobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/stringobject.c,v
retrieving revision 2.124
retrieving revision 2.125
diff -C2 -d -r2.124 -r2.125
*** stringobject.c	2001/08/17 18:39:25	2.124
--- stringobject.c	2001/08/24 18:32:06	2.125
***************
*** 148,151 ****
--- 148,306 ----
  }
  
+ PyObject *
+ PyString_FromFormatV(const char *format, va_list vargs)
+ {
+ 	va_list count = vargs;
+ 	int n = 0;
+ 	const char* f;
+ 	char *s;
+ 	PyObject* string;
+ 
+ 	/* step 1: figure out how large a buffer we need */
+ 	for (f = format; *f; f++) {
+ 		if (*f == '%') {
+ 			const char* p = f;
+ 			while (*++f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
+ 				;
+ 
+ 			/* skip the 'l' in %ld, since it doesn't change the
+ 			   width.  although only %d is supported (see
+ 			   "expand" section below), others can be easily
+ 			   add */
+ 			if (*f == 'l' && *(f+1) == 'd')
+ 				++f;
+ 			
+ 			switch (*f) {
+ 			case 'c':
+ 				(void)va_arg(count, int);
+ 				/* fall through... */
+ 			case '%':
+ 				n++;
+ 				break;
+ 			case 'd': case 'i': case 'x':
+ 				(void) va_arg(count, int);
+ 				/* 20 bytes should be enough to hold a 64-bit
+ 				   integer */
+ 				n += 20;
+ 				break;
+ 			case 's':
+ 				s = va_arg(count, char*);
+ 				n += strlen(s);
+ 				break;
+ 			case 'p':
+ 				(void) va_arg(count, int);
+ 				/* maximum 64-bit pointer representation:
+ 				 * 0xffffffffffffffff
+ 				 * so 19 characters is enough.
+ 				 */
+ 				n += 19;
+ 				break;
+ 			default:
+ 				/* if we stumble upon an unknown
+ 				   formatting code, copy the rest of
+ 				   the format string to the output
+ 				   string. (we cannot just skip the
+ 				   code, since there's no way to know
+ 				   what's in the argument list) */ 
+ 				n += strlen(p);
+ 				goto expand;
+ 			}
+ 		} else
+ 			n++;
+ 	}
+  expand:
+ 	/* step 2: fill the buffer */
+ 	string = PyString_FromStringAndSize(NULL, n);
+ 	if (!string)
+ 		return NULL;
+ 	
+ 	s = PyString_AsString(string);
+ 
+ 	for (f = format; *f; f++) {
+ 		if (*f == '%') {
+ 			const char* p = f++;
+ 			int i, longflag = 0;
+ 			/* parse the width.precision part (we're only
+ 			   interested in the precision value, if any) */
+ 			n = 0;
+ 			while (isdigit(Py_CHARMASK(*f)))
+ 				n = (n*10) + *f++ - '0';
+ 			if (*f == '.') {
+ 				f++;
+ 				n = 0;
+ 				while (isdigit(Py_CHARMASK(*f)))
+ 					n = (n*10) + *f++ - '0';
+ 			}
+ 			while (*f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
+ 				f++;
+ 			/* handle the long flag, but only for %ld.  others
+ 			   can be added when necessary. */
+ 			if (*f == 'l' && *(f+1) == 'd') {
+ 				longflag = 1;
+ 				++f;
+ 			}
+ 			
+ 			switch (*f) {
+ 			case 'c':
+ 				*s++ = va_arg(vargs, int);
+ 				break;
+ 			case 'd':
+ 				if (longflag)
+ 					sprintf(s, "%ld", va_arg(vargs, long));
+ 				else
+ 					sprintf(s, "%d", va_arg(vargs, int));
+ 				s += strlen(s);
+ 				break;
+ 			case 'i':
+ 				sprintf(s, "%i", va_arg(vargs, int));
+ 				s += strlen(s);
+ 				break;
+ 			case 'x':
+ 				sprintf(s, "%x", va_arg(vargs, int));
+ 				s += strlen(s);
+ 				break;
+ 			case 's':
+ 				p = va_arg(vargs, char*);
+ 				i = strlen(p);
+ 				if (n > 0 && i > n)
+ 					i = n;
+ 				memcpy(s, p, i);
+ 				s += i;
+ 				break;
+ 			case 'p':
+ 				sprintf(s, "%p", va_arg(vargs, void*));
+ 				s += strlen(s);
+ 				break;
+ 			case '%':
+ 				*s++ = '%';
+ 				break;
+ 			default:
+ 				strcpy(s, p);
+ 				s += strlen(s);
+ 				goto end;
+ 			}
+ 		} else
+ 			*s++ = *f;
+ 	}
+ 	
+  end:
+ 	_PyString_Resize(&string, s - PyString_AsString(string));
+ 	return string;
+ }
+ 	
+ PyObject *
+ PyString_FromFormat(const char *format, ...) 
+ {
+ 	va_list vargs;
+ 
+ #ifdef HAVE_STDARG_PROTOTYPES
+ 	va_start(vargs, format);
+ #else
+ 	va_start(vargs);
+ #endif
+ 	return PyString_FromFormatV(format, vargs);
+ }
+ 
+ 
  PyObject *PyString_Decode(const char *s,
  			  int size,