Re: Multi-line string extension (string substitution)

Donald Beaudry (don@vicorp.com)
Wed, 20 Apr 94 15:23:18 EDT

Ok, I could not resist. What follows is a patch to stringobject.c
that allows formatstring() (the '%' operator on strings) to
take a mapping object as its right hand operand. So it works like
this:

print 'here is a %(sub)s hack' % {'sub':'real neat'}

will print

here is a real neat hack

All of the formatting options work as well.

print 'here is a %(sub)15s hack' % {'sub':'real neat'}

here is a real neat hack

or

print 'here is a %(sub)*s hack' % {'sub':(15, 'real neat')}

here is a real neat hack

Get the idea? Good.

--Don

______ ______
\_\_\_\ /#/#/#/
\_\_\_\ ______
\_\_\_V#/#/#/ Donald Beaudry don@vicorp.com
\_\_/#/#/#/ V. I. Corporation uunet!vicorp!don
\_/#/#/#/ 47 Pleasant Street PHONE: (413) 586-4144
V#/#/#/ Northampton, MA 01060 FAX: (413) 586-3805

*** stringobject.c.orig Wed Apr 20 12:46:02 1994
--- stringobject.c Wed Apr 20 13:00:38 1994
***************
*** 598,603 ****
--- 598,625 ----
return buf;
}

+ static object *
+ get_mapping_item(mo, key)
+ object *mo;
+ char *key;
+ {
+ mapping_methods *mm = mo->ob_type->tp_as_mapping;
+ object *ko = newstringobject(key);
+ object *val;
+
+ if (! mm || ! mm->mp_subscript) {
+ err_setstr(TypeError, "subscript not implemented");
+ return NULL;
+ }
+
+ val = (*mm->mp_subscript)(mo, ko);
+ XDECREF(val); /* still in mapping */
+ XDECREF(ko);
+
+ return val;
+ }
+
+
/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) */

object *
***************
*** 607,613 ****
{
char *fmt, *res;
int fmtcnt, rescnt, reslen, arglen, argidx;
! object *result;
if (format == NULL || !is_stringobject(format) || args == NULL) {
err_badcall();
return NULL;
--- 629,635 ----
{
char *fmt, *res;
int fmtcnt, rescnt, reslen, arglen, argidx;
! object *result, *dict = 0;
if (format == NULL || !is_stringobject(format) || args == NULL) {
err_badcall();
return NULL;
***************
*** 627,632 ****
--- 649,656 ----
arglen = -1;
argidx = -2;
}
+ if (args->ob_type->tp_as_mapping)
+ dict = args;
while (--fmtcnt >= 0) {
if (*fmt != '%') {
if (--rescnt < 0) {
***************
*** 651,656 ****
--- 675,723 ----
char *buf;
int sign;
int len;
+ if (*fmt == '(') {
+ char key[20]; /* XXX need a bigger key? */
+ char *kp = 0;
+ int cnt = sizeof key / sizeof key[0];
+
+ if (! dict) {
+ err_setstr(TypeError,
+ "format requires a mapping");
+ goto error;
+ }
+ ++fmt;
+ --fmtcnt;
+ kp = &key[0];
+ while (--fmtcnt >= 0 && *fmt != ')' && --cnt)
+ *kp++ = *fmt++;
+ *kp = '\0';
+ ++fmt;
+ if (fmtcnt < 0) {
+ err_setstr(ValueError,
+ "incomplete format key");
+ goto error;
+ }
+ if (cnt <= 0) {
+ err_setstr(ValueError,
+ "format key too long");
+ goto error;
+ }
+ args = get_mapping_item(dict, key);
+ if (! args) {
+ err_setstr(KeyError, key);
+ goto error;
+ }
+ if (is_tupleobject(args))
+ {
+ arglen = gettuplesize(args);
+ argidx = 0;
+ }
+ else
+ {
+ arglen = -1;
+ argidx = -2;
+ }
+ }
while (--fmtcnt >= 0) {
switch (c = *fmt++) {
case '-': flags |= F_LJUST; continue;
***************
*** 841,846 ****
--- 908,918 ----
--rescnt;
*res++ = ' ';
}
+ if (dict && (argidx < arglen)) {
+ err_setstr(TypeError,
+ "not all arguments converted");
+ goto error;
+ }
} /* '%' */
} /* until end */
if (argidx < arglen) {