1 #include	<stdlib.h>
2 #include	<stdio.h>
3 #include	<assert.h>
4 #include	<string.h>
5 
6 char	*UTS_sprintf_wrap();
7 char	*do_efmt();
8 char	*do_gfmt();
9 char	*Fill();
10 
11 /* main(argc, argv)
12  * char	**argv;
13  * {
14  * 	double	d;
15  * 	char	*Fmt, *Ret;
16  * 	char	obuf[200];
17  *
18  * 	assert(argc > 2);
19  * 	Fmt = argv[1];
20  * 	d = strtod(argv[2], (char **)0);
21  *
22  * 	putchar('{');
23  * 	printf(Fmt, d);
24  * 	printf("}\n");
25  *
26  * 	Ret = UTS_sprintf_wrap(obuf, Fmt, d);
27  * 	assert(Ret == obuf);
28  *
29  * 	printf("{%s}\n", obuf);
30  * }
31  */
32 
33 char *
UTS_sprintf_wrap(obuf,fmt,d,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)34 UTS_sprintf_wrap(obuf, fmt, d,
35 	a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)
36 char	*obuf, *fmt;
37 double	d;
38 {
39 	int	fmtlen, Width=0, Precision=6, Alt=0, Plus=0, Minus=0,
40 		Zero = 0;
41 	int	FmtChar, BaseFmt = 0;
42 	char	*f = fmt, *AfterWidth = 0, *AfterPrecision = 0;
43 	char	*Dot;
44 
45 	if(*f++ != '%') {
46 		return
47 sprintf(obuf, fmt, d, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15);
48 	}
49 	fmtlen = strlen(fmt);
50 	FmtChar = fmt[fmtlen - 1];
51 	switch(FmtChar) {
52 	case 'f':
53 	case 'F':
54 		return
55 sprintf(obuf, fmt, d, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15);
56 	case 'e':
57 	case 'E':
58 		BaseFmt = 'e';
59 		goto BaseFmt_IsSet;
60 	case 'g':
61 	case 'G':
62 		BaseFmt = 'g';
63 BaseFmt_IsSet:
64 		if(*f == '#') { Alt = 1; ++f; }   /* Always has '.' */
65 		if(*f == '+') { Plus = 1; ++f; }  /* Force explicit sign */
66 		if(*f == '-') { Minus = 1; ++f; } /* Left justify */
67 		if(*f == '0') { Zero = 1; ++f;} /* Fill using 0s*/
68 		if(Dot = strchr(f, '.')) {
69 			Precision = strtol(Dot+1, &AfterPrecision, 0);
70 		}
71 		if(!Dot || (Dot && Dot > f)) { /* Next char=='.' => no width*/
72 			Width = strtol(f, &AfterWidth, 0);
73 		}
74 		if(Dot) { f = AfterPrecision; }
75 		else if(AfterWidth) { f = AfterWidth; }
76 		if(*f != FmtChar) goto regular_sprintf;
77 		 /* It doesn't look like a f.p. sprintf call */
78 		 /* from Perl_sv_vcatpvfn		     */
79 
80 		if(BaseFmt == 'e') {
81 			return do_efmt(d, obuf, Width, Precision, Alt,
82 				Plus, Minus, Zero, FmtChar == 'E');
83 		} else {
84 			return do_gfmt(d, obuf, Width, Precision, Alt,
85 				Plus, Minus, Zero, FmtChar == 'G');
86 		}
87 	default:
88 regular_sprintf:
89 		return
90 sprintf(obuf, fmt, d, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15);
91 	}
92 }
93 
94 char	*
do_efmt(d,obuf,Width,Precision,Alt,Plus,Minus,Zero,UpperCase)95 do_efmt(d, obuf, Width, Precision, Alt, Plus, Minus, Zero, UpperCase)
96 char	*obuf;
97 double	d;
98 {
99 	char	*Ecvt;
100 	char	*ob;
101 	int	decpt, sign, E;
102 	int	len;
103 	int	AllZeroes = 0;
104 
105 	Ecvt = ecvt( d , Precision+1, &decpt, &sign);
106 
107 	/* fprintf(stderr, "decpt=%d, sign=%d\n", decpt, sign); */
108 
109 	len = strlen(Ecvt);
110 	if(strspn(Ecvt, "0") == len) AllZeroes = 1;
111 
112 	ob = obuf;
113 	if(sign)	*ob++ = '-';
114 	else if(Plus)	*ob++ = '+';
115 
116 	*ob++ = Ecvt[0];
117 
118 	if(Precision > 0 || Alt) *ob++ = '.';
119 	strcpy(ob, &Ecvt[1]);
120 
121 	ob += strlen(ob);	/* ADVANCE TO END OF WHAT WE JUST ADDED */
122 	*ob++ = UpperCase ? 'E' : 'e';
123 
124 	if(AllZeroes)	E = 0;
125 	else		E = decpt - 1;
126 
127 	if(E < 0)	{ *ob++ = '-'; E = -E; }
128 	else		{ *ob++ = '+'; }
129 
130 	sprintf(ob, "%.2d", E);	/* Too much horsepower used here */
131 
132 	if(Width > strlen(obuf)) return Fill(obuf, Width, Minus, Zero);
133 	else			 return obuf;
134 }
135 
136 char	*
do_gfmt(d,obuf,Width,Precision,Alt,Plus,Minus,Zero,UpperCase)137 do_gfmt(d, obuf, Width, Precision, Alt, Plus, Minus, Zero, UpperCase)
138 char	*obuf;
139 double	d;
140 {
141 	char	*Ecvt = gcvt(d, Precision ? Precision : 1, obuf);
142 	int	len = strlen(obuf);
143 
144 	 /* gcvt fails (maybe give a warning? For now return empty string): */
145 	if(!Ecvt) { *obuf = '\0'; return obuf; }
146 
147 	/* printf("Ecvt='%s'\n", Ecvt); */
148 	if(Plus && (Ecvt[0] != '-')) {
149 		memmove(obuf+1, obuf, len+1); /* "+1" to get '\0' at end */
150 		obuf[0] = '+';
151 		++len;
152 	}
153 	if(Alt && !strchr(Ecvt, '.')) {
154 		int	LenUpTo_E = strcspn(obuf, "eE");
155 		int	E_etc_len = strlen(&obuf[LenUpTo_E]);
156 			/* ABOVE: Will be 0 if there's no E/e because */
157 			/* strcspn will return length of whole string */
158 
159 		if(E_etc_len)
160 			memmove(obuf+LenUpTo_E+1, obuf+LenUpTo_E, E_etc_len);
161 		obuf[LenUpTo_E] = '.';
162 		obuf[LenUpTo_E + 1 + E_etc_len ] = '\0';
163 	}
164 	{ char *E_loc;
165 	  if(UpperCase && (E_loc = strchr(obuf, 'e'))) { *E_loc = 'E'; }
166 	}
167 	if(Width > len)
168 		return Fill(obuf, Width, Minus, Zero);
169 	else
170 		return obuf;
171 }
172 
173 char *
Fill(obuf,Width,LeftJustify,Zero)174 Fill(obuf, Width, LeftJustify, Zero)
175 char	*obuf;
176 {
177 	int	W = strlen(obuf);
178 	int	diff = Width - W;
179 	 /* LeftJustify means there was a '-' flag, and in that case,	*/
180 	 /* printf man page (UTS4.4) says ignore '0'			*/
181 	char	FillChar = (Zero && !LeftJustify) ? '0' : ' ';
182 	int	i;
183 	int	LeftFill = ! LeftJustify;
184 
185 	if(Width <= W) return obuf;
186 
187 	if(LeftFill) {
188 		memmove(obuf+diff, obuf, W+1); /* "+1" to get '\0' at end */
189 		for(i=0 ; i < diff ; ++i) { obuf[i] = FillChar; }
190 	} else {
191 		for(i=W ; i < Width ; ++i)
192 			obuf[i] = FillChar;
193 		obuf[Width] = '\0';
194 	}
195 	return obuf;
196 }
197