:i	static char str_misc_sccs_id[] = "%W% %G%";

#include <stdlib.h>
#include <stdarg.h>
#include "V_M_UC.h"
#include "str.h"
#include "mem.h"

#ifdef NOTNOW
/*
* Find common substring.  Compare the first n  bytes  of  two  null-terminated
* strings,  and return the length of the common initial substring.  The result
* will be in [0,n].
*/
comstrn(p,q,n)
	char *p;
	char *q;
	Sizt  n;
{	Sizt  i;

	for (i=0; i<n; i++)
		if (p[i] != q[i])
			return i;
	return n;
}
/*
* Allocate space for a copy of a null-terminated string, copy it  to  the  new
* block,  and  return  its  address.   The  msg  is  for diagnostics.  This is
* essentiall a clone of the library dupstr() function.
*/
char *
dupstr(p,m)
	char *p;
	char *m;
{	char *q;
	Sizt  n;

:f	Fenter("dupstr");
	if (!m) m = p;
	n = strlen(p) + StrPadLen;
	if (q = (CP)GetChunk(MEMUNIT(n),m)) {
:9		V9M "Got %d bytes  for %s.",n+StrPadLen,m D;
		Bcopy(p, q, n);
:9		V9M "Put %d bytes into %s.",n+StrPadLen,m D;
	}
:f	Fexit;
	return q;
}
#endif

/*
* Here are some older names for some of our  functions,  kept  for  the  usual
* backwards  compatibiliity  reasons,  so that we can successfully link old .o
* files to this newer version of the str package.
*/
int  chkstrng(s,m) Str*s; char*m; {return str_chksm(s,m);}
Str* appstrng(d,s,l,m) Str*d; char*s; char*m; {return str_appscm(d,s,l,m);}
Str* cpystrng(d,s,m) Str*d; Str*s; char*m; {return str_dupssm(d,s,m);}
Str* dupstrng(d,s,m) Str*d; Str*s; char*m; {return str_dupssm(d,s,m);}
Str* freestrng(s,m) Str*s; char*m; {return str_zapsm(s,m);}
Str* getstrng(s,n,m) Str*s; char*m; {return str_dupscm(s,(char*)0,n,m);}
Str* makstrng(d,s,l,m) Str*d; char*s; char*m; {return str_dupscm(d,s,l,m);}

#define INC 16	// Size increment

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This is like sprintf, but the resulting formatted string is written to a Str *
* structure.   This means that we can check to make sure that there was enough *
* space in the string's value, and expand it if necessary. The return value is *
* the  Str's  address,  or null if we couldn't get the space.  The only way we *
* return a null value is if *mp is null and we can't get space for a Str.  But *
* if the formatting fails, we return mp, which will be a null string.          *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Str* fmtStr(
	Str  *mp,	// Where to build string
	char *fmt,	// Format string
	...) 		// Fields
{	Str  *r=0;
	int   size=100;	// Guess we need no more than 100 bytes
	int   n;
	va_list ap;
:f	Fenter("fmtStr");
:5	V5 "fmt: \"%s\"",fmt V;
	unless (mp) {
		unless (mp = (Str*)malloc(sizeof(Str))) {
:1			V1 "### Can't get %d bytes for Str struct ###",sizeof(Str) V;
			Fail;
		}
	}
	if (mp->m < size) minStrM(mp,size,Fctname);
	mp->l = 0;		// Don't preserve old value
	while (1) {		// Try to print in the allocated space
		va_start(ap, fmt);			// Attempt the format
		n = vsnprintf(mp->v, size, fmt, ap);
		va_end(ap);
		if (n > -1 && n < size) {	// If that worked, return the string
			mp->l = strlen(mp->v);	// Note its actual size
			r = mp;
			Done;
		} else {					// Try again with more space
			char *p;
			size = n + INC;			// Grab more space
			unless (p = (char*)malloc(size+1)) {
:1				V1 "### Can't get %d bytes for formatted string ###",size V;
				if (mp->v) {		// Does string have space?
					mp->v[mp->l=0] = 0;	// If so, make it null string
				} else {
					mp->l = mp->m = 0;	// If not, another null string
				}
				Fail;
			}
			free(mp->v);
			mp->v = p;
			mp->m = size;
		}
	}
done:
:5	V5 "l=%d %s",r->l,QSP(r) V;
fail:
:f	Fexit;
	return r;
}

