Edinburgh Speech Tools 2.4-release
 
Loading...
Searching...
No Matches
slib_format.cc
1/*************************************************************************/
2/* */
3/* Centre for Speech Technology Research */
4/* University of Edinburgh, UK */
5/* Copyright (c) 1996,1997 */
6/* All Rights Reserved. */
7/* */
8/* Permission is hereby granted, free of charge, to use and distribute */
9/* this software and its documentation without restriction, including */
10/* without limitation the rights to use, copy, modify, merge, publish, */
11/* distribute, sublicense, and/or sell copies of this work, and to */
12/* permit persons to whom this work is furnished to do so, subject to */
13/* the following conditions: */
14/* 1. The code must retain the above copyright notice, this list of */
15/* conditions and the following disclaimer. */
16/* 2. Any modifications must be clearly marked as such. */
17/* 3. Original authors' names are not deleted. */
18/* 4. The authors' names are not used to endorse or promote products */
19/* derived from this software without specific prior written */
20/* permission. */
21/* */
22/* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23/* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24/* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25/* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26/* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27/* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28/* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29/* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30/* THIS SOFTWARE. */
31/* */
32/*************************************************************************/
33/* Author : Alan W Black */
34/* Date : December 1996 */
35/*-----------------------------------------------------------------------*/
36/* */
37/* A format function for formated output (like printf) */
38/* */
39/* Its amazing how much I have to write myself to get this to work when */
40/* most people believe this a c library function. */
41/* */
42/*=======================================================================*/
43
44#include <cstdlib>
45#include <cstdio>
46#include "EST_cutils.h"
47#include "siod.h"
48#include "siodp.h"
49
50static int format_string(LISP fd,const char *formatstr, const char *str);
51static int format_lisp(LISP fd,const char *formatstr, LISP a);
52static int format_int(LISP fd,const char *formatstr, int i);
53static int format_float(LISP fd,const char *formatstr, float f);
54static int format_double(LISP fd,const char *formatstr, double d);
55static int format_char(LISP fd, char c);
56static int get_field_width(const char *directive);
57static char *get_directive(const char *fstr);
58static char directive_type(const char *fstr);
59static void output_string(LISP fd,const char *str);
60static int count_arg_places(const char *formatstring);
61
62static EST_String outstring;
63static EST_Regex anumber_rx("[0-9]+");
64
65LISP l_format(LISP args)
66{
67 // A format function for formated output
68 // Hmm not sure how to do this without writing lots myself
69 const char *formatstring = get_c_string(car(cdr(args)));
70 LISP lfd = car(args);
71 LISP fargs = cdr(cdr(args));
72 int i;
73 LISP a;
74
75 if (count_arg_places(formatstring) != siod_llength(fargs))
76 err("format: wrong number of args for format string",NIL);
77
78 outstring="";
79
80 for (i=0,a=fargs; formatstring[i] != '\0'; i++)
81 {
82 if (formatstring[i] != '%')
83 format_char(lfd,formatstring[i]);
84 else if (formatstring[i+1] == '%')
85 {
86 format_char(lfd,formatstring[i]);
87 i++; // skip quoted %
88 }
89 else if (directive_type(formatstring+i) == 's')
90 {
91 i+= format_string(lfd,formatstring+i,get_c_string(car(a)));
92 a = cdr(a);
93 }
94 else if (directive_type(formatstring+i) == 'l')
95 {
96 i+= format_lisp(lfd,formatstring+i,car(a));
97 a = cdr(a);
98 }
99 else if ((directive_type(formatstring+i) == 'd') ||
100 (directive_type(formatstring+i) == 'x'))
101 {
102 i += format_int(lfd,formatstring+i,(int)get_c_int(car(a)));
103 a = cdr(a);
104 }
105 else if (directive_type(formatstring+i) == 'f')
106 {
107 i += format_float(lfd,formatstring+i,(float)get_c_double(car(a)));
108 a = cdr(a);
109 }
110 else if (directive_type(formatstring+i) == 'g')
111 {
112 i += format_double(lfd,formatstring+i,get_c_double(car(a)));
113 a = cdr(a);
114 }
115 else if (directive_type(formatstring+i) == 'c')
116 {
117 format_char(lfd,(char)get_c_int(car(a)));
118 i++;
119 a = cdr(a);
120 }
121 else
122 {
123 cerr << "SIOD format: unsupported format directive %"
124 << directive_type(formatstring+i) << endl;
125 err("",NIL);
126 }
127 }
128
129 if (lfd == NIL)
130 return strintern(outstring);
131 else
132 return NIL;
133}
134
135static int format_string(LISP fd,const char *formatstr, const char *str)
136{
137 // Output str to fd using directive at start of formatstr
138 // Returns the number character in the format directive
139 char *directive = get_directive(formatstr);
140 int width = get_field_width(directive);
141 char *buff;
142
143 if (width > (signed)strlen(str))
144 buff = walloc(char,width+10);
145 else
146 buff = walloc(char,strlen(str)+1);
147
148 sprintf(buff,directive,str);
149
150 output_string(fd,buff);
151 width = strlen(directive)-1;
152 wfree(buff);
153 wfree(directive);
154
155 return width;
156}
157
158static int format_lisp(LISP fd,const char *formatstr, LISP a)
159{
160 // Output a as str to fd using directive at start of formatstr
161 // Returns the number character in the format directive
162 char *directive = get_directive(formatstr);
163 int width = get_field_width(directive);
164 EST_String buff;
165
166 if (width != 0)
167 err("format: width in %l not supported",NIL);
168
169 buff = siod_sprint(a);
170
171 output_string(fd,buff);
172 width = strlen(directive)-1;
173 wfree(directive);
174
175 return width;
176}
177
178static int format_int(LISP fd, const char *formatstr, int i)
179{
180 // Output i to fd using directive at start of formatstr
181 // Returns the number character in the format directive
182 char *directive = get_directive(formatstr);
183 int width = get_field_width(directive);
184 char *buff;
185
186 if (width > 20)
187 buff = walloc(char,width+10);
188 else
189 buff = walloc(char,20);
190
191 sprintf(buff,directive,i);
192
193 output_string(fd,buff);
194 width = strlen(directive)-1;
195 wfree(buff);
196 wfree(directive);
197
198 return width;
199}
200
201static int format_float(LISP fd, const char *formatstr, float f)
202{
203 // Output f to fd using directive at start of formatstr
204 // Returns the number character in the format directive
205 char *directive = get_directive(formatstr);
206 int width = get_field_width(directive);
207 char *buff;
208
209 if (width > 20)
210 buff = walloc(char,width+10);
211 else
212 buff = walloc(char,20);
213
214 sprintf(buff,directive,f);
215
216 output_string(fd,buff);
217 width = strlen(directive)-1;
218 wfree(buff);
219 wfree(directive);
220
221 return width;
222}
223
224static int format_double(LISP fd, const char *formatstr, double d)
225{
226 // Output f to fd using directive at start of formatstr
227 // Returns the number character in the format directive
228 char *directive = get_directive(formatstr);
229 int width = get_field_width(directive);
230 char *buff;
231
232 if (width > 30)
233 buff = walloc(char,width+10);
234 else
235 buff = walloc(char,30);
236
237 sprintf(buff,directive,d);
238
239 output_string(fd,buff);
240 width = strlen(directive)-1;
241 wfree(buff);
242 wfree(directive);
243
244 return width;
245}
246
247static int format_char(LISP fd, char c)
248{
249 // Output c to fd using directive at start of formatstr
250 // Returns the number character in the format directive
251 char buff[10];
252
253 sprintf(buff,"%c",c);
254
255 output_string(fd,buff);
256
257 return 0;
258}
259
260static int get_field_width(const char *directive)
261{
262 // Look inside the directive for any explicit width info
263
264 if (strlen(directive) == 2)
265 return 0;
266 else
267 {
268 EST_String nums = directive;
269 nums = nums.at(1,strlen(directive)-2);
270 if (nums.matches(anumber_rx))
271 return atoi(nums);
272 else if (nums.contains("."))
273 {
274 EST_String n1 = nums.before(".");
275 EST_String n2 = nums.after(".");
276 return atoi(n1) + atoi(n2);
277 }
278 else
279 {
280 cerr << "SIOD format: can't find width in directive "
281 << directive << endl;
282 err("",NIL);
283 }
284 }
285 return 0;
286}
287
288static char *get_directive(const char *fstr)
289{
290 // Copy the format directive from the start of this string
291 int i;
292
293 for (i=0; fstr[i] != '\0'; i++)
294 if ((fstr[i] >= 'a') &&
295 (fstr[i] <= 'z'))
296 break;
297 if (fstr[i] == '\0')
298 err("format: premature end of format structure",NIL);
299 char *direct = walloc(char,i+2);
300 memmove(direct,fstr,i+1);
301 direct[i+1] = '\0';
302 return direct;
303}
304
305static char directive_type(const char *fstr)
306{
307 // return the next lower case character. This identifies the
308 // type of the argument to be inserted in the format string
309 int i;
310
311 for (i=0; fstr[i] != '\0'; i++)
312 if ((fstr[i] >= 'a') &&
313 (fstr[i] <= 'z'))
314 {
315 return fstr[i];
316 }
317
318 err("SIOD format: premature end of format structure",NIL);
319 return '\0';
320
321}
322
323static void output_string(LISP fd, const char *str)
324{
325 if (fd == NIL)
326 outstring += str;
327 else if (fd == truth)
328 fprintf(stdout,"%s",str);
329 else if (TYPEP(fd,tc_c_file))
330 fprintf(get_c_file(fd,NULL),"%s",str);
331 else
332 err("format: not a file",fd);
333}
334
335static int count_arg_places(const char *formatstring)
336{
337 // count number of places in the format string.
338 int c,i;
339
340 for (c=i=0; formatstring[i] != '\0'; i++)
341 if (formatstring[i] == '%')
342 {
343 if (formatstring[i+1] == '%')
344 i++;
345 else
346 c++;
347 }
348
349 return c;
350}
351
352void init_subrs_format()
353{
354 init_lsubr("format",l_format,
355 "(format FD FORMATSTRING ARG0 ARG1 ...)\n\
356 Output ARGs to FD using FROMATSTRING. FORMATSTRING is like a printf\n\
357 formatstrng. FD may be a filedescriptor, or t (standard output) or\n\
358 nil (return as a string). Note not all printf format directive are\n\
359 supported. %l is additionally support for Lisp objects.\n\
360 [see Scheme I/O]");
361}
EST_String before(int pos, int len=0) const
Part before position.
Definition EST_String.h:286
int contains(const char *s, int pos=-1) const
Does it contain this substring?
Definition EST_String.h:375
EST_String after(int pos, int len=1) const
Part after pos+len.
Definition EST_String.h:318
int matches(const char *e, int pos=0) const
Exactly match this string?
EST_String at(int from, int len=0) const
Return part at position.
Definition EST_String.h:302