Edinburgh Speech Tools  2.1-release
slib_format.cc
Go to the documentation of this file.
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 
50 using namespace std;
51 
52 static int format_string(LISP fd,const char *formatstr, const char *str);
53 static int format_lisp(LISP fd,const char *formatstr, LISP a);
54 static int format_int(LISP fd,const char *formatstr, int i);
55 static int format_float(LISP fd,const char *formatstr, float f);
56 static int format_double(LISP fd,const char *formatstr, double d);
57 static int format_char(LISP fd, char c);
58 static int get_field_width(const char *directive);
59 static char *get_directive(const char *fstr);
60 static char directive_type(const char *fstr);
61 static void output_string(LISP fd,const char *str);
62 static int count_arg_places(const char *formatstring);
63 
64 static EST_String outstring;
65 static EST_Regex anumber_rx("[0-9]+");
66 
67 LISP l_format(LISP args)
68 {
69  // A format function for formated output
70  // Hmm not sure how to do this without writing lots myself
71  const char *formatstring = get_c_string(car(cdr(args)));
72  LISP lfd = car(args);
73  LISP fargs = cdr(cdr(args));
74  int i;
75  LISP a;
76 
77  if (count_arg_places(formatstring) != siod_llength(fargs))
78  err("format: wrong number of args for format string",NIL);
79 
80  outstring="";
81 
82  for (i=0,a=fargs; formatstring[i] != '\0'; i++)
83  {
84  if (formatstring[i] != '%')
85  format_char(lfd,formatstring[i]);
86  else if (formatstring[i+1] == '%')
87  {
88  format_char(lfd,formatstring[i]);
89  i++; // skip quoted %
90  }
91  else if (directive_type(formatstring+i) == 's')
92  {
93  i+= format_string(lfd,formatstring+i,get_c_string(car(a)));
94  a = cdr(a);
95  }
96  else if (directive_type(formatstring+i) == 'l')
97  {
98  i+= format_lisp(lfd,formatstring+i,car(a));
99  a = cdr(a);
100  }
101  else if ((directive_type(formatstring+i) == 'd') ||
102  (directive_type(formatstring+i) == 'x'))
103  {
104  i += format_int(lfd,formatstring+i,(int)get_c_int(car(a)));
105  a = cdr(a);
106  }
107  else if (directive_type(formatstring+i) == 'f')
108  {
109  i += format_float(lfd,formatstring+i,(float)get_c_double(car(a)));
110  a = cdr(a);
111  }
112  else if (directive_type(formatstring+i) == 'g')
113  {
114  i += format_double(lfd,formatstring+i,get_c_double(car(a)));
115  a = cdr(a);
116  }
117  else if (directive_type(formatstring+i) == 'c')
118  {
119  format_char(lfd,(char)get_c_int(car(a)));
120  i++;
121  a = cdr(a);
122  }
123  else
124  {
125  cerr << "SIOD format: unsupported format directive %"
126  << directive_type(formatstring+i) << endl;
127  err("",NIL);
128  }
129  }
130 
131  if (lfd == NIL)
132  return strintern(outstring);
133  else
134  return NIL;
135 }
136 
137 static int format_string(LISP fd,const char *formatstr, const char *str)
138 {
139  // Output str to fd using directive at start of formatstr
140  // Returns the number character in the format directive
141  char *directive = get_directive(formatstr);
142  int width = get_field_width(directive);
143  char *buff;
144 
145  if (width > (signed)strlen(str))
146  buff = walloc(char,width+10);
147  else
148  buff = walloc(char,strlen(str)+1);
149 
150  sprintf(buff,directive,str);
151 
152  output_string(fd,buff);
153  width = strlen(directive)-1;
154  wfree(buff);
155  wfree(directive);
156 
157  return width;
158 }
159 
160 static int format_lisp(LISP fd,const char *formatstr, LISP a)
161 {
162  // Output a as str to fd using directive at start of formatstr
163  // Returns the number character in the format directive
164  char *directive = get_directive(formatstr);
165  int width = get_field_width(directive);
166  EST_String buff;
167 
168  if (width != 0)
169  err("format: width in %l not supported",NIL);
170 
171  buff = siod_sprint(a);
172 
173  output_string(fd,buff);
174  width = strlen(directive)-1;
175  wfree(directive);
176 
177  return width;
178 }
179 
180 static int format_int(LISP fd, const char *formatstr, int i)
181 {
182  // Output i to fd using directive at start of formatstr
183  // Returns the number character in the format directive
184  char *directive = get_directive(formatstr);
185  int width = get_field_width(directive);
186  char *buff;
187 
188  if (width > 20)
189  buff = walloc(char,width+10);
190  else
191  buff = walloc(char,20);
192 
193  sprintf(buff,directive,i);
194 
195  output_string(fd,buff);
196  width = strlen(directive)-1;
197  wfree(buff);
198  wfree(directive);
199 
200  return width;
201 }
202 
203 static int format_float(LISP fd, const char *formatstr, float f)
204 {
205  // Output f to fd using directive at start of formatstr
206  // Returns the number character in the format directive
207  char *directive = get_directive(formatstr);
208  int width = get_field_width(directive);
209  char *buff;
210 
211  if (width > 20)
212  buff = walloc(char,width+10);
213  else
214  buff = walloc(char,20);
215 
216  sprintf(buff,directive,f);
217 
218  output_string(fd,buff);
219  width = strlen(directive)-1;
220  wfree(buff);
221  wfree(directive);
222 
223  return width;
224 }
225 
226 static int format_double(LISP fd, const char *formatstr, double d)
227 {
228  // Output f to fd using directive at start of formatstr
229  // Returns the number character in the format directive
230  char *directive = get_directive(formatstr);
231  int width = get_field_width(directive);
232  char *buff;
233 
234  if (width > 30)
235  buff = walloc(char,width+10);
236  else
237  buff = walloc(char,30);
238 
239  sprintf(buff,directive,d);
240 
241  output_string(fd,buff);
242  width = strlen(directive)-1;
243  wfree(buff);
244  wfree(directive);
245 
246  return width;
247 }
248 
249 static int format_char(LISP fd, char c)
250 {
251  // Output c to fd using directive at start of formatstr
252  // Returns the number character in the format directive
253  char buff[10];
254 
255  sprintf(buff,"%c",c);
256 
257  output_string(fd,buff);
258 
259  return 0;
260 }
261 
262 static int get_field_width(const char *directive)
263 {
264  // Look inside the directive for any explicit width info
265 
266  if (strlen(directive) == 2)
267  return 0;
268  else
269  {
270  EST_String nums = directive;
271  nums = nums.at(1,strlen(directive)-2);
272  if (nums.matches(anumber_rx))
273  return atoi(nums);
274  else if (nums.contains("."))
275  {
276  EST_String n1 = nums.before(".");
277  EST_String n2 = nums.after(".");
278  return atoi(n1) + atoi(n2);
279  }
280  else
281  {
282  cerr << "SIOD format: can't find width in directive "
283  << directive << endl;
284  err("",NIL);
285  }
286  }
287  return 0;
288 }
289 
290 static char *get_directive(const char *fstr)
291 {
292  // Copy the format directive from the start of this string
293  int i;
294 
295  for (i=0; fstr[i] != '\0'; i++)
296  if ((fstr[i] >= 'a') &&
297  (fstr[i] <= 'z'))
298  break;
299  if (fstr[i] == '\0')
300  err("format: premature end of format structure",NIL);
301  char *direct = walloc(char,i+2);
302  memmove(direct,fstr,i+1);
303  direct[i+1] = '\0';
304  return direct;
305 }
306 
307 static char directive_type(const char *fstr)
308 {
309  // return the next lower case character. This identifies the
310  // type of the argument to be inserted in the format string
311  int i;
312 
313  for (i=0; fstr[i] != '\0'; i++)
314  if ((fstr[i] >= 'a') &&
315  (fstr[i] <= 'z'))
316  {
317  return fstr[i];
318  }
319 
320  err("SIOD format: premature end of format structure",NIL);
321  return '\0';
322 
323 }
324 
325 static void output_string(LISP fd, const char *str)
326 {
327  if (fd == NIL)
328  outstring += str;
329  else if (fd == truth)
330  fprintf(stdout,"%s",str);
331  else if (TYPEP(fd,tc_c_file))
332  fprintf(get_c_file(fd,NULL),"%s",str);
333  else
334  err("format: not a file",fd);
335 }
336 
337 static int count_arg_places(const char *formatstring)
338 {
339  // count number of places in the format string.
340  int c,i;
341 
342  for (c=i=0; formatstring[i] != '\0'; i++)
343  if (formatstring[i] == '%')
344  {
345  if (formatstring[i+1] == '%')
346  i++;
347  else
348  c++;
349  }
350 
351  return c;
352 }
353 
355 {
356  init_lsubr("format",l_format,
357  "(format FD FORMATSTRING ARG0 ARG1 ...)\n\
358  Output ARGs to FD using FROMATSTRING. FORMATSTRING is like a printf\n\
359  formatstrng. FD may be a filedescriptor, or t (standard output) or\n\
360  nil (return as a string). Note not all printf format directive are\n\
361  supported. %l is additionally support for Lisp objects.\n\
362  [see Scheme I/O]");
363 }
void init_subrs_format()
Definition: slib_format.cc:354
#define walloc(TYPE, SIZE)
Definition: EST_walloc.h:52
double get_c_double(LISP x)
Definition: slib.cc:1854
int contains(const char *s, ssize_t pos=-1) const
Does it contain this substring?
Definition: EST_String.h:365
A Regular expression class to go with the CSTR EST_String class.
Definition: EST_Regex.h:56
long int get_c_int(LISP x)
Definition: slib.cc:1850
#define NIL
Definition: siod_defs.h:92
int siod_llength(LISP list)
Definition: siod.cc:202
LISP strintern(const char *data)
Definition: slib_str.cc:22
LISP l_format(LISP args)
Definition: slib_format.cc:67
#define tc_c_file
Definition: siod_defs.h:120
FILE * get_c_file(LISP p, FILE *deflt)
Definition: slib_file.cc:349
void err(const char *message, LISP x) EST_NORETURN
Definition: slib.cc:608
const char * get_c_string(LISP x)
Definition: slib.cc:638
EST_String siod_sprint(LISP exp)
Definition: slib_file.cc:208
NULL
Definition: EST_WFST.cc:55
f
Definition: EST_item_aux.cc:48
int matches(const char *e, ssize_t pos=0) const
Exactly match this string?
Definition: EST_String.cc:651
#define TYPEP(x, y)
Definition: siod_defs.h:100
void init_lsubr(const char *name, LISP(*fcn)(LISP), const char *doc)
Definition: slib.cc:906
LISP car(LISP x)
Definition: slib_list.cc:115
EST_String after(int pos, int len=1) const
Part after pos+len.
Definition: EST_String.h:308
EST_String before(int pos, int len=0) const
Part before position.
Definition: EST_String.h:276
LISP truth
Definition: slib.cc:135
EST_String at(int from, int len=0) const
Return part at position.
Definition: EST_String.h:292
void wfree(void *p)
Definition: walloc.c:131
LISP cdr(LISP x)
Definition: slib_list.cc:124