Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6536 serge 1
/*
2
FUNCTION
3
<>, <>---double or float to string
4
 
5
INDEX
6
	ecvtbuf
7
INDEX
8
	fcvtbuf
9
 
10
ANSI_SYNOPSIS
11
	#include 
12
 
13
	char *ecvtbuf(double <[val]>, int <[chars]>, int *<[decpt]>,
14
                       int *<[sgn]>, char *<[buf]>);
15
 
16
	char *fcvtbuf(double <[val]>, int <[decimals]>, int *<[decpt]>,
17
                       int *<[sgn]>, char *<[buf]>);
18
 
19
TRAD_SYNOPSIS
20
	#include 
21
 
22
	char *ecvtbuf(<[val]>, <[chars]>, <[decpt]>, <[sgn]>, <[buf]>);
23
	double <[val]>;
24
	int <[chars]>;
25
	int *<[decpt]>;
26
	int *<[sgn]>;
27
	char *<[buf]>;
28
 
29
	char *fcvtbuf(<[val]>, <[decimals]>, <[decpt]>, <[sgn]>, <[buf]>);
30
	double <[val]>;
31
	int <[decimals]>;
32
	int *<[decpt]>;
33
	int *<[sgn]>;
34
	char *<[buf]>;
35
 
36
DESCRIPTION
37
	<> and <> produce (null-terminated) strings
38
	of digits representating the <> number <[val]>.
39
 
40
	The only difference between <> and <> is the
41
	interpretation of the second argument (<[chars]> or
42
	<[decimals]>). For <>, the second argument <[chars]>
43
	specifies the total number of characters to write (which is
44
	also the number of significant digits in the formatted string,
45
	since these two functions write only digits). For <>,
46
	the second argument <[decimals]> specifies the number of
47
	characters to write after the decimal point; all digits for
48
	the integer part of <[val]> are always included.
49
 
50
	Since <> and <> write only digits in the
51
	output string, they record the location of the decimal point
52
	in <<*<[decpt]>>>, and the sign of the number in <<*<[sgn]>>>.
53
	After formatting a number, <<*<[decpt]>>> contains the number
54
	of digits to the left of the decimal point.  <<*<[sgn]>>>
55
	contains <<0>> if the number is positive, and <<1>> if it is
56
	negative.  For both functions, you supply a pointer <[buf]> to
57
	an area of memory to hold the converted string.
58
 
59
RETURNS
60
	Both functions return a pointer to <[buf]>, the string
61
	containing a character representation of <[val]>.
62
 
63
PORTABILITY
64
	Neither function is ANSI C.
65
 
66
Supporting OS subroutines required: <>, <>, <>,
67
<>, <>, <>, <>.
68
*/
69
 
70
#include <_ansi.h>
71
#include 
72
#include 
73
#include 
74
#include "mprec.h"
75
#include "local.h"
76
 
77
static void
78
_DEFUN (print_f, (ptr, buf, invalue, ndigit, type, dot, mode),
79
	struct _reent *ptr _AND
80
	char *buf _AND
81
	double invalue _AND
82
	int ndigit _AND
83
	char type _AND
84
	int dot _AND
85
	int mode)
86
{
87
  int decpt;
88
  int sign;
89
  char *p, *start, *end;
90
 
91
  start = p = _dtoa_r (ptr, invalue, mode, ndigit, &decpt, &sign, &end);
92
 
93
  if (decpt == 9999)
94
    {
95
      strcpy (buf, p);
96
      return;
97
    }
98
  while (*p && decpt > 0)
99
    {
100
      *buf++ = *p++;
101
      decpt--;
102
    }
103
  /* Even if not in buffer */
104
  while (decpt > 0)
105
    {
106
      *buf++ = '0';
107
      decpt--;
108
    }
109
 
110
  if (dot || *p)
111
    {
112
      if (p == start)
113
	*buf++ = '0';
114
      *buf++ = '.';
115
      while (decpt < 0 && ndigit > 0)
116
	{
117
	  *buf++ = '0';
118
	  decpt++;
119
	  ndigit--;
120
	}
121
 
122
      /* Print rest of stuff */
123
      while (*p && ndigit > 0)
124
	{
125
	  *buf++ = *p++;
126
	  ndigit--;
127
	}
128
      /* And trailing zeros */
129
      while (ndigit > 0)
130
	{
131
	  *buf++ = '0';
132
	  ndigit--;
133
	}
134
    }
135
  *buf++ = 0;
136
}
137
 
138
/* Print number in e format with width chars after.
139
 
140
   TYPE is one of 'e' or 'E'.  It may also be one of 'g' or 'G' indicating
141
   that _gcvt is calling us and we should remove trailing zeroes.
142
 
143
   WIDTH is the number of digits of precision after the decimal point.  */
144
 
145
static void
146
_DEFUN (print_e, (ptr, buf, invalue, width, type, dot),
147
	struct _reent *ptr _AND
148
	char *buf _AND
149
	double invalue _AND
150
	int width _AND
151
	char type _AND
152
	int dot)
153
{
154
  int sign;
155
  char *end;
156
  char *p;
157
  int decpt;
158
  int top;
159
  int ndigit = width;
160
 
161
  p = _dtoa_r (ptr, invalue, 2, width + 1, &decpt, &sign, &end);
162
 
163
  if (decpt == 9999)
164
    {
165
      strcpy (buf, p);
166
      return;
167
    }
168
 
169
  *buf++ = *p++;
170
  if (dot || ndigit != 0)
171
    *buf++ = '.';
172
 
173
  while (*p && ndigit > 0)
174
    {
175
      *buf++ = *p++;
176
      ndigit--;
177
    }
178
 
179
  /* Add trailing zeroes to fill out to ndigits unless this is 'g' format.
180
     Also, convert g/G to e/E.  */
181
 
182
  if (type == 'g')
183
    type = 'e';
184
  else if (type == 'G')
185
    type = 'E';
186
  else
187
    {
188
      while (ndigit > 0)
189
	{
190
	  *buf++ = '0';
191
	  ndigit--;
192
	}
193
    }
194
 
195
  /* Add the exponent.  */
196
 
197
  *buf++ = type;
198
  decpt--;
199
  if (decpt < 0)
200
    {
201
      *buf++ = '-';
202
      decpt = -decpt;
203
    }
204
  else
205
    {
206
      *buf++ = '+';
207
    }
208
  if (decpt > 99)
209
    {
210
      int top = decpt / 100;
211
      *buf++ = top + '0';
212
      decpt -= top * 100;
213
    }
214
  top = decpt / 10;
215
  *buf++ = top + '0';
216
  decpt -= top * 10;
217
  *buf++ = decpt + '0';
218
 
219
  *buf++ = 0;
220
}
221
 
222
#ifndef _REENT_ONLY
223
 
224
/* Undocumented behaviour: when given NULL as a buffer, return a
225
   pointer to static space in the rent structure.  This is only to
226
   support ecvt and fcvt, which aren't ANSI anyway.  */
227
 
228
char *
229
_DEFUN (fcvtbuf, (invalue, ndigit, decpt, sign, fcvt_buf),
230
	double invalue _AND
231
	int ndigit _AND
232
	int *decpt _AND
233
	int *sign _AND
234
	char *fcvt_buf)
235
{
236
  struct _reent *reent = _REENT;
237
  char *save;
238
  char *p;
239
  char *end;
240
  int done = 0;
241
 
242
  if (fcvt_buf == NULL)
243
    {
244
      if (reent->_cvtlen <= ndigit + 35)
245
	{
246
	  if ((fcvt_buf = (char *) _realloc_r (reent, reent->_cvtbuf,
247
					       ndigit + 36)) == NULL)
248
	    return NULL;
249
	  reent->_cvtlen = ndigit + 36;
250
	  reent->_cvtbuf = fcvt_buf;
251
	}
252
 
253
      fcvt_buf = reent->_cvtbuf ;
254
    }
255
 
256
  save = fcvt_buf;
257
 
258
  if (invalue < 1.0 && invalue > -1.0)
259
    {
260
      p = _dtoa_r (reent, invalue, 2, ndigit, decpt, sign, &end);
261
    }
262
  else
263
    {
264
      p = _dtoa_r (reent, invalue, 3, ndigit, decpt, sign, &end);
265
    }
266
 
267
  /* Now copy */
268
 
269
  done = -*decpt;
270
  while (p < end)
271
    {
272
      *fcvt_buf++ = *p++;
273
      done++;
274
    }
275
  /* And unsuppress the trailing zeroes */
276
  while (done < ndigit)
277
    {
278
      *fcvt_buf++ = '0';
279
      done++;
280
    }
281
  *fcvt_buf++ = 0;
282
  return save;
283
}
284
 
285
char *
286
_DEFUN (ecvtbuf, (invalue, ndigit, decpt, sign, fcvt_buf),
287
	double invalue _AND
288
	int ndigit _AND
289
	int *decpt _AND
290
	int *sign _AND
291
	char *fcvt_buf)
292
{
293
  struct _reent *reent = _REENT;
294
  char *save;
295
  char *p;
296
  char *end;
297
  int done = 0;
298
 
299
  if (fcvt_buf == NULL)
300
    {
301
      if (reent->_cvtlen <= ndigit)
302
	{
303
	  if ((fcvt_buf = (char *) _realloc_r (reent, reent->_cvtbuf,
304
					       ndigit + 1)) == NULL)
305
	    return NULL;
306
	  reent->_cvtlen = ndigit + 1;
307
	  reent->_cvtbuf = fcvt_buf;
308
	}
309
 
310
      fcvt_buf = reent->_cvtbuf ;
311
    }
312
 
313
  save = fcvt_buf;
314
 
315
  p = _dtoa_r (reent, invalue, 2, ndigit, decpt, sign, &end);
316
 
317
  /* Now copy */
318
 
319
  while (p < end)
320
    {
321
      *fcvt_buf++ = *p++;
322
      done++;
323
    }
324
  /* And unsuppress the trailing zeroes */
325
  while (done < ndigit)
326
    {
327
      *fcvt_buf++ = '0';
328
      done++;
329
    }
330
  *fcvt_buf++ = 0;
331
  return save;
332
}
333
 
334
#endif
335
 
336
char *
337
_DEFUN (_gcvt, (ptr, invalue, ndigit, buf, type, dot),
338
	struct _reent *ptr _AND
339
	double invalue _AND
340
	int ndigit _AND
341
	char *buf _AND
342
	char type _AND
343
	int dot)
344
{
345
  char *save = buf;
346
 
347
  if (invalue < 0)
348
    {
349
      invalue = -invalue;
350
    }
351
 
352
  if (invalue == 0)
353
    {
354
      *buf++ = '0';
355
      *buf = '\0';
356
    }
357
  else
358
    /* Which one to print ?
359
       ANSI says that anything with more that 4 zeros after the . or more
360
       than precision digits before is printed in e with the qualification
361
       that trailing zeroes are removed from the fraction portion.  */
362
 
363
  if (0.0001 >= invalue || invalue >= _mprec_log10 (ndigit))
364
    {
365
      /* We subtract 1 from ndigit because in the 'e' format the precision is
366
	 the number of digits after the . but in 'g' format it is the number
367
	 of significant digits.
368
 
369
	 We defer changing type to e/E so that print_e() can know it's us
370
	 calling and thus should remove trailing zeroes.  */
371
 
372
      print_e (ptr, buf, invalue, ndigit - 1, type, dot);
373
    }
374
  else
375
    {
376
      int decpt;
377
      int sign;
378
      char *end;
379
      char *p;
380
 
381
      if (invalue < 1.0)
382
	{
383
	  /* what we want is ndigits after the point */
384
	  p = _dtoa_r (ptr, invalue, 3, ndigit, &decpt, &sign, &end);
385
	}
386
      else
387
	{
388
	  p = _dtoa_r (ptr, invalue, 2, ndigit, &decpt, &sign, &end);
389
	}
390
 
391
      if (decpt == 9999)
392
	{
393
	  strcpy (buf, p);
394
	  return save;
395
	}
396
      while (*p && decpt > 0)
397
	{
398
	  *buf++ = *p++;
399
	  decpt--;
400
	  ndigit--;
401
	}
402
      /* Even if not in buffer */
403
      while (decpt > 0 && ndigit > 0)
404
	{
405
	  *buf++ = '0';
406
	  decpt--;
407
	  ndigit--;
408
	}
409
 
410
      if (dot || *p)
411
	{
412
	  if (buf == save)
413
	    *buf++ = '0';
414
	  *buf++ = '.';
415
	  while (decpt < 0 && ndigit > 0)
416
	    {
417
	      *buf++ = '0';
418
	      decpt++;
419
	      ndigit--;
420
	    }
421
 
422
	  /* Print rest of stuff */
423
	  while (*p && ndigit > 0)
424
	    {
425
	      *buf++ = *p++;
426
	      ndigit--;
427
	    }
428
	  /* And trailing zeros */
429
	  if (dot)
430
	    {
431
	      while (ndigit > 0)
432
		{
433
		  *buf++ = '0';
434
		  ndigit--;
435
		}
436
	    }
437
	}
438
      *buf++ = 0;
439
    }
440
 
441
  return save;
442
}
443
 
444
char *
445
_DEFUN (_dcvt, (ptr, buffer, invalue, precision, width, type, dot),
446
	struct _reent *ptr _AND
447
	char *buffer _AND
448
	double invalue _AND
449
	int precision _AND
450
	int width _AND
451
	char type _AND
452
	int dot)
453
{
454
  switch (type)
455
    {
456
    case 'f':
457
    case 'F':
458
      print_f (ptr, buffer, invalue, precision, type, precision == 0 ? dot : 1, 3);
459
      break;
460
    case 'g':
461
    case 'G':
462
      if (precision == 0)
463
	precision = 1;
464
      _gcvt (ptr, invalue, precision, buffer, type, dot);
465
      break;
466
    case 'e':
467
    case 'E':
468
      print_e (ptr, buffer, invalue, precision, type, dot);
469
    }
470
  return buffer;
471
}