Support /proc/uptime

This commit is contained in:
Gregory Nutt 2013-12-14 10:34:08 -06:00
parent 9f01df47ea
commit 46b77e2544
8 changed files with 496 additions and 38 deletions

View File

@ -6225,4 +6225,5 @@
(2013-12-13). (2013-12-13).
* fs/procfs/procfs_utils.c: Move some re-usable functions out of * fs/procfs/procfs_utils.c: Move some re-usable functions out of
fs_procfsproc.c into a utility file (2013-12-14). fs_procfsproc.c into a utility file (2013-12-14).
* fs/procfs/fs_procfsuptime.c: Supports /proc/uptime (2013-12-14).

View File

@ -35,6 +35,10 @@ config FS_PROCFS_EXCLUDE_PROCESS
This will reduce code space, but then giving access to process info This will reduce code space, but then giving access to process info
was kinda the whole point of procfs, but hey, whatever. was kinda the whole point of procfs, but hey, whatever.
config FS_PROCFS_EXCLUDE_UPTIME
bool "Exclude uptime"
default n
config FS_PROCFS_EXCLUDE_PARTITIONS config FS_PROCFS_EXCLUDE_PARTITIONS
bool "Exclude partitions" bool "Exclude partitions"
depends on MTD_PARTITION depends on MTD_PARTITION

View File

@ -37,7 +37,7 @@ ifeq ($(CONFIG_FS_PROCFS),y)
# Files required for procfs file system support # Files required for procfs file system support
ASRCS += ASRCS +=
CSRCS += fs_procfs.c fs_procfsproc.c fs_procfsutil.c CSRCS += fs_procfs.c fs_procfsutil.c fs_procfsproc.c fs_procfsuptime.c
# Include procfs build support # Include procfs build support

View File

@ -76,6 +76,7 @@
****************************************************************************/ ****************************************************************************/
extern const struct procfs_operations process_operations; extern const struct procfs_operations process_operations;
extern const struct procfs_operations uptime_operations;
extern const struct procfs_operations mtd_procfsoperations; extern const struct procfs_operations mtd_procfsoperations;
extern const struct procfs_operations part_procfsoperations; extern const struct procfs_operations part_procfsoperations;
extern const struct procfs_operations smartfs_procfsoperations; extern const struct procfs_operations smartfs_procfsoperations;
@ -101,6 +102,9 @@ static const struct procfs_entry_s g_procfsentries[] =
#if defined(CONFIG_MTD_PARTITION) && !defined(CONFIG_FS_PROCFS_EXCLUDE_PARTITON) #if defined(CONFIG_MTD_PARTITION) && !defined(CONFIG_FS_PROCFS_EXCLUDE_PARTITON)
{ "partitions", &part_procfsoperations }, { "partitions", &part_procfsoperations },
#endif #endif
#if !defined(CONFIG_FS_PROCFS_EXCLUDE_UPTIME)
{ "uptime", &uptime_operations },
#endif
}; };
static const uint8_t g_procfsentrycount = sizeof(g_procfsentries) / static const uint8_t g_procfsentrycount = sizeof(g_procfsentries) /

View File

@ -68,6 +68,9 @@
/**************************************************************************** /****************************************************************************
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
/* Determines the size of an intermeidate buffer that must be large enough
* to handle the longest line generated by this logic.
*/
#define STATUS_LINELEN 32 #define STATUS_LINELEN 32
@ -344,7 +347,7 @@ static ssize_t process_status(FAR struct process_file_s *attr,
return totalsize; return totalsize;
} }
/* Show the signal mast */ /* Show the signal mask */
#ifndef CONFIG_DISABLE_SIGNALS #ifndef CONFIG_DISABLE_SIGNALS
linesize = snprintf(attr->line, STATUS_LINELEN, "%-12s%08x\n", "SigMask:", linesize = snprintf(attr->line, STATUS_LINELEN, "%-12s%08x\n", "SigMask:",

359
fs/procfs/fs_procfsuptime.c Normal file
View File

@ -0,0 +1,359 @@
/****************************************************************************
* fs/procfs/fs_procfsuptime.c
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <sys/statfs.h>
#include <sys/stat.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/clock.h>
#include <nuttx/kmalloc.h>
#include <nuttx/fs/fs.h>
#include <nuttx/fs/procfs.h>
#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_PROCFS)
#ifndef CONFIG_FS_PROCFS_EXCLUDE_PROCESS
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Determines the size of an intermeidate buffer that must be large enough
* to handle the longest line generated by this logic.
*/
#define UPTIME_LINELEN 16
/****************************************************************************
* Private Types
****************************************************************************/
/* This structure describes one open "file" */
struct uptime_file_s
{
struct procfs_file_s base; /* Base open file structure */
char line[UPTIME_LINELEN]; /* Pre-allocated buffer for formatted lines */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* File system methods */
static int uptime_open(FAR struct file *filep, FAR const char *relpath,
int oflags, mode_t mode);
static int uptime_close(FAR struct file *filep);
static ssize_t uptime_read(FAR struct file *filep, FAR char *buffer,
size_t buflen);
static int uptime_dup(FAR const struct file *oldp,
FAR struct file *newp);
static int uptime_stat(FAR const char *relpath, FAR struct stat *buf);
/****************************************************************************
* Private Variables
****************************************************************************/
/****************************************************************************
* Public Variables
****************************************************************************/
/* See fs_mount.c -- this structure is explicitly externed there.
* We use the old-fashioned kind of initializers so that this will compile
* with any compiler.
*/
const struct procfs_operations uptime_operations =
{
uptime_open, /* open */
uptime_close, /* close */
uptime_read, /* read */
NULL, /* write */
uptime_dup, /* dup */
NULL, /* opendir */
NULL, /* closedir */
NULL, /* readdir */
NULL, /* rewinddir */
uptime_stat /* stat */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: uptime_open
****************************************************************************/
static int uptime_open(FAR struct file *filep, FAR const char *relpath,
int oflags, mode_t mode)
{
FAR struct uptime_file_s *attr;
fvdbg("Open '%s'\n", relpath);
/* PROCFS is read-only. Any attempt to open with any kind of write
* access is not permitted.
*
* REVISIT: Write-able proc files could be quite useful.
*/
if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0)
{
fdbg("ERROR: Only O_RDONLY supported\n");
return -EACCES;
}
/* "uptime" is the only acceptable value for the relpath */
if (strcmp(relpath, "uptime") != 0)
{
fdbg("ERROR: relpath is '%s'\n", relpath);
return -ENOENT;
}
/* Allocate a container to hold the file attributes */
attr = (FAR struct uptime_file_s *)kzalloc(sizeof(struct uptime_file_s));
if (!attr)
{
fdbg("ERROR: Failed to allocate file attributes\n");
return -ENOMEM;
}
/* Save the attributes as the open-specific state in filep->f_priv */
filep->f_priv = (FAR void *)attr;
return OK;
}
/****************************************************************************
* Name: uptime_close
****************************************************************************/
static int uptime_close(FAR struct file *filep)
{
FAR struct uptime_file_s *attr;
/* Recover our private data from the struct file instance */
attr = (FAR struct uptime_file_s *)filep->f_priv;
DEBUGASSERT(attr);
/* Release the file attributes structure */
kfree(attr);
filep->f_priv = NULL;
return OK;
}
/****************************************************************************
* Name: uptime_read
****************************************************************************/
static ssize_t uptime_read(FAR struct file *filep, FAR char *buffer,
size_t buflen)
{
FAR struct uptime_file_s *attr;
size_t linesize;
off_t offset;
ssize_t ret;
#ifdef CONFIG_SYSTEM_TIME64
/* 32-bit timer */
uint64_t upticks = clock_systimer64();
#if defined(CONFIG_HAVE_DOUBLE) && defined(CONFIG_LIBC_FLOATINGPOINT)
double now = (double)upticks / (double)CLOCKS_PER_SEC;
#else
uint64_t sec = upticks / CLOCKS_PER_SEC;
unsigned int remainder = (unsigned int)(upticks % CLOCKS_PER_SEC);
unsigned int csec = (100 * remainder + (CLOCKS_PER_SEC / 2)) / CLOCKS_PER_SEC;
#endif
#else
/* 32-bit timer */
uint32_t upticks = clock_systimer();
#if defined(CONFIG_HAVE_DOUBLE) && defined(CONFIG_LIBC_FLOATINGPOINT)
double now = (double)upticks / (double)CLOCKS_PER_SEC;
#else
uint32_t sec = upticks / CLOCKS_PER_SEC;
unsigned int remainder = (unsigned int)(upticks % CLOCKS_PER_SEC);
unsigned int csec = (100 * remainder + (CLOCKS_PER_SEC / 2)) / CLOCKS_PER_SEC;
#endif
#endif
fvdbg("buffer=%p buflen=%d\n", buffer, (int)buflen);
/* Recover our private data from the struct file instance */
attr = (FAR struct uptime_file_s *)filep->f_priv;
DEBUGASSERT(attr);
#if defined(CONFIG_HAVE_DOUBLE) && defined(CONFIG_LIBC_FLOATINGPOINT)
/* Convert the system up time to seconds + hundredths of seconds */
linesize = snprintf(attr->line, UPTIME_LINELEN, "%10.2f\n", now);
#else
/* Make sure that rounding did not force the hundredths of a second above 99 */
if (csec > 99)
{
sec++;
csec -= 100;
}
/* Convert the system up time to seconds + hundredths of seconds */
linesize = snprintf(attr->line, UPTIME_LINELEN, "%7lu.%02u\n", sec, csec);
#endif
/* Transfer the system up time to user receive buffer */
offset = filep->f_pos;
ret = procfs_memcpy(attr->line, linesize, buffer, buflen, &offset);
/* Update the file offset */
if (ret > 0)
{
filep->f_pos += ret;
}
return ret;
}
/****************************************************************************
* Name: uptime_dup
*
* Description:
* Duplicate open file data in the new file structure.
*
****************************************************************************/
static int uptime_dup(FAR const struct file *oldp, FAR struct file *newp)
{
FAR struct uptime_file_s *oldattr;
FAR struct uptime_file_s *newattr;
fvdbg("Dup %p->%p\n", oldp, newp);
/* Recover our private data from the old struct file instance */
oldattr = (FAR struct uptime_file_s *)oldp->f_priv;
DEBUGASSERT(oldattr);
/* Allocate a new container to hold the task and attribute selection */
newattr = (FAR struct uptime_file_s *)kzalloc(sizeof(struct uptime_file_s));
if (!newattr)
{
fdbg("ERROR: Failed to allocate file attributes\n");
return -ENOMEM;
}
/* The copy the file attribtes from the old attributes to the new */
memcpy(&newattr->base, &oldattr->base, sizeof(struct procfs_file_s));
/* Save the new attributes in the new file structure */
newp->f_priv = (FAR void *)newattr;
return OK;
}
/****************************************************************************
* Name: uptime_stat
*
* Description: Return information about a file or directory
*
****************************************************************************/
static int uptime_stat(const char *relpath, struct stat *buf)
{
int ret;
/* "uptime" is the only acceptable value for the relpath */
if (strcmp(relpath, "uptime") != 0)
{
fdbg("ERROR: relpath is '%s'\n", relpath);
return -ENOENT;
}
/* "uptime" is the name for a read-only file */
buf->st_mode = S_IFREG|S_IROTH|S_IRGRP|S_IRUSR;
buf->st_size = 0;
buf->st_blksize = 0;
buf->st_blocks = 0;
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
#endif /* CONFIG_FS_PROCFS_EXCLUDE_PROCESS */
#endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS */

View File

@ -147,6 +147,7 @@ static Bigint *Balloc(int k)
rv->k = k; rv->k = k;
rv->maxwds = x; rv->maxwds = x;
} }
rv->sign = rv->wds = 0; rv->sign = rv->wds = 0;
return rv; return rv;
} }
@ -189,6 +190,7 @@ static Bigint *multadd(Bigint * b, int m, int a)
#endif #endif
} }
while (++i < wds); while (++i < wds);
if (a) if (a)
{ {
if (wds >= b->maxwds) if (wds >= b->maxwds)
@ -201,6 +203,7 @@ static Bigint *multadd(Bigint * b, int m, int a)
b->x[wds++] = a; b->x[wds++] = a;
b->wds = wds; b->wds = wds;
} }
return b; return b;
} }
@ -240,6 +243,7 @@ static int hi0bits(unsigned long x)
return 32; return 32;
} }
} }
return k; return k;
} }
@ -254,11 +258,13 @@ static int lo0bits(unsigned long *y)
{ {
return 0; return 0;
} }
if (x & 2) if (x & 2)
{ {
*y = x >> 1; *y = x >> 1;
return 1; return 1;
} }
*y = x >> 2; *y = x >> 2;
return 2; return 2;
} }
@ -297,6 +303,7 @@ static int lo0bits(unsigned long *y)
return 32; return 32;
} }
} }
*y = x; *y = x;
return k; return k;
} }
@ -336,11 +343,13 @@ static Bigint *mult(Bigint * a, Bigint * b)
{ {
k++; k++;
} }
c = Balloc(k); c = Balloc(k);
for (x = c->x, xa = x + wc; x < xa; x++) for (x = c->x, xa = x + wc; x < xa; x++)
{ {
*x = 0; *x = 0;
} }
xa = a->x; xa = a->x;
xae = xa + wa; xae = xa + wa;
xb = b->x; xb = b->x;
@ -363,8 +372,10 @@ static Bigint *mult(Bigint * a, Bigint * b)
Storeinc(xc, z2, z); Storeinc(xc, z2, z);
} }
while (x < xae); while (x < xae);
*xc = carry; *xc = carry;
} }
if ((y = *xb >> 16)) if ((y = *xb >> 16))
{ {
x = xa; x = xa;
@ -380,6 +391,7 @@ static Bigint *mult(Bigint * a, Bigint * b)
carry = z2 >> 16; carry = z2 >> 16;
} }
while (x < xae); while (x < xae);
*xc = z2; *xc = z2;
} }
} }
@ -398,10 +410,12 @@ static Bigint *mult(Bigint * a, Bigint * b)
*xc++ = z & 0xffff; *xc++ = z & 0xffff;
} }
while (x < xae); while (x < xae);
*xc = carry; *xc = carry;
} }
} }
#endif #endif
for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc); for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc);
c->wds = wc; c->wds = wc;
return c; return c;
@ -438,6 +452,7 @@ static Bigint *pow5mult(Bigint * b, int k)
Bfree(b); Bfree(b);
b = b1; b = b1;
} }
if (!(k >>= 1)) if (!(k >>= 1))
{ {
break; break;
@ -448,8 +463,10 @@ static Bigint *pow5mult(Bigint * b, int k)
p51 = p5->next = mult(p5, p5); p51 = p5->next = mult(p5, p5);
p51->next = 0; p51->next = 0;
} }
p5 = p51; p5 = p51;
} }
return b; return b;
} }
@ -470,12 +487,14 @@ static Bigint *lshift(Bigint * b, int k)
{ {
k1++; k1++;
} }
b1 = Balloc(k1); b1 = Balloc(k1);
x1 = b1->x; x1 = b1->x;
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
{ {
*x1++ = 0; *x1++ = 0;
} }
x = b->x; x = b->x;
xe = x + b->wds; xe = x + b->wds;
#ifdef Pack_32 #ifdef Pack_32
@ -489,6 +508,7 @@ static Bigint *lshift(Bigint * b, int k)
z = *x++ >> k1; z = *x++ >> k1;
} }
while (x < xe); while (x < xe);
if ((*x1 = z)) if ((*x1 = z))
{ {
++n1; ++n1;
@ -505,6 +525,7 @@ static Bigint *lshift(Bigint * b, int k)
z = *x++ >> k1; z = *x++ >> k1;
} }
while (x < xe); while (x < xe);
if ((*x1 = z)) if ((*x1 = z))
{ {
++n1; ++n1;
@ -512,11 +533,14 @@ static Bigint *lshift(Bigint * b, int k)
} }
#endif #endif
else else
do {
{ do
*x1++ = *x++; {
} *x1++ = *x++;
while (x < xe); }
while (x < xe);
}
b1->wds = n1 - 1; b1->wds = n1 - 1;
Bfree(b); Bfree(b);
return b1; return b1;
@ -534,13 +558,18 @@ static int cmp(Bigint * a, Bigint * b)
{ {
ldbg("cmp called with a->x[a->wds-1] == 0\n"); ldbg("cmp called with a->x[a->wds-1] == 0\n");
} }
if (j > 1 && !b->x[j - 1]) if (j > 1 && !b->x[j - 1])
{ {
ldbg("cmp called with b->x[b->wds-1] == 0\n"); ldbg("cmp called with b->x[b->wds-1] == 0\n");
} }
#endif #endif
if (i -= j) if (i -= j)
return i; {
return i;
}
xa0 = a->x; xa0 = a->x;
xa = xa0 + j; xa = xa0 + j;
xb0 = b->x; xb0 = b->x;
@ -548,9 +577,14 @@ static int cmp(Bigint * a, Bigint * b)
for (;;) for (;;)
{ {
if (*--xa != *--xb) if (*--xa != *--xb)
return *xa < *xb ? -1 : 1; {
return *xa < *xb ? -1 : 1;
}
if (xa <= xa0) if (xa <= xa0)
break; {
break;
}
} }
return 0; return 0;
} }
@ -573,6 +607,7 @@ static Bigint *diff(Bigint * a, Bigint * b)
c->x[0] = 0; c->x[0] = 0;
return c; return c;
} }
if (i < 0) if (i < 0)
{ {
c = a; c = a;
@ -581,7 +616,10 @@ static Bigint *diff(Bigint * a, Bigint * b)
i = 1; i = 1;
} }
else else
i = 0; {
i = 0;
}
c = Balloc(a->k); c = Balloc(a->k);
c->sign = i; c->sign = i;
wa = a->wds; wa = a->wds;
@ -604,6 +642,7 @@ static Bigint *diff(Bigint * a, Bigint * b)
Storeinc(xc, z, y); Storeinc(xc, z, y);
} }
while (xb < xbe); while (xb < xbe);
while (xa < xae) while (xa < xae)
{ {
y = (*xa & 0xffff) + borrow; y = (*xa & 0xffff) + borrow;
@ -623,6 +662,7 @@ static Bigint *diff(Bigint * a, Bigint * b)
*xc++ = y & 0xffff; *xc++ = y & 0xffff;
} }
while (xb < xbe); while (xb < xbe);
while (xa < xae) while (xa < xae)
{ {
y = *xa++ + borrow; y = *xa++ + borrow;
@ -631,8 +671,12 @@ static Bigint *diff(Bigint * a, Bigint * b)
*xc++ = y & 0xffff; *xc++ = y & 0xffff;
} }
#endif #endif
while (!*--xc) while (!*--xc)
wa--; {
wa--;
}
c->wds = wa; c->wds = wa;
return c; return c;
} }
@ -663,7 +707,10 @@ static Bigint *d2b(double d, int *e, int *bits)
z >>= k; z >>= k;
} }
else else
x[0] = y; {
x[0] = y;
}
i = b->wds = (x[1] = z) ? 2 : 1; i = b->wds = (x[1] = z) ? 2 : 1;
} }
else else
@ -727,6 +774,7 @@ static Bigint *d2b(double d, int *e, int *bits)
x[1] = z >> 16; x[1] = z >> 16;
i = 1; i = 1;
} }
k += 32; k += 32;
} }
while (!x[i]) while (!x[i])
@ -747,10 +795,12 @@ static Bigint *d2b(double d, int *e, int *bits)
*bits = (i + 2) * 16 - hi0bits(x[i]); *bits = (i + 2) * 16 - hi0bits(x[i]);
#endif #endif
} }
return b; return b;
} }
static const double tens[] = { static const double tens[] =
{
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22 1e20, 1e21, 1e22
@ -790,6 +840,7 @@ static int quorem(Bigint * b, Bigint * S)
{ {
return 0; return 0;
} }
sx = S->x; sx = S->x;
sxe = sx + --n; sxe = sx + --n;
bx = b->x; bx = b->x;
@ -801,6 +852,7 @@ static int quorem(Bigint * b, Bigint * S)
ldbg("oversized quotient in quorem\n"); ldbg("oversized quotient in quorem\n");
} }
#endif #endif
if (q) if (q)
{ {
borrow = 0; borrow = 0;
@ -829,11 +881,15 @@ static int quorem(Bigint * b, Bigint * S)
#endif #endif
} }
while (sx <= sxe); while (sx <= sxe);
if (!*bxe) if (!*bxe)
{ {
bx = b->x; bx = b->x;
while (--bxe > bx && !*bxe) while (--bxe > bx && !*bxe)
--n; {
--n;
}
b->wds = n; b->wds = n;
} }
} }
@ -877,6 +933,7 @@ static int quorem(Bigint * b, Bigint * S)
b->wds = n; b->wds = n;
} }
} }
return q; return q;
} }
@ -921,14 +978,14 @@ static int quorem(Bigint * b, Bigint * S)
char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve) char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
{ {
/* Arguments ndigits, decpt, sign are similar to those of ecvt and fcvt; /* Arguments ndigits, decpt, sign are similar to those of ecvt and fcvt;
* trailing zeros are suppressed from the returned string. If not null, *rve * trailing zeros are suppressed from the returned string. If not null, *rve
* is set to point to the end of the return value. If d is +-Infinity or * is set to point to the end of the return value. If d is +-Infinity or
* NaN, then *decpt is set to 9999. * NaN, then *decpt is set to 9999.
* *
* mode: 0 ==> shortest string that yields d when read in and rounded to * mode: 0 ==> shortest string that yields d when read in and rounded to
* nearest. 1 ==> like 0, but with Steele & White stopping rule; e.g. with * nearest. 1 ==> like 0, but with Steele & White stopping rule; e.g. with
* IEEE P754 arithmetic , mode 0 gives 1e23 whereas mode 1 gives * IEEE P754 arithmetic , mode 0 gives 1e23 whereas mode 1 gives
* 9.999999999999999e22. 2 ==> max(1,ndigits) significant digits. This gives * 9.999999999999999e22. 2 ==> max(1,ndigits) significant digits. This gives
* a return value similar to that of ecvt, except that trailing zeros are * a return value similar to that of ecvt, except that trailing zeros are
* suppressed. 3 ==> through ndigits past the decimal point. This gives a * suppressed. 3 ==> through ndigits past the decimal point. This gives a
* return value similar to that from fcvt, except that trailing zeros are * return value similar to that from fcvt, except that trailing zeros are
@ -938,9 +995,9 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
* sometimes faster than modes 2-3. 4,5,8,9 ==> left-to-right digit * sometimes faster than modes 2-3. 4,5,8,9 ==> left-to-right digit
* generation. 6-9 ==> don't try fast floating-point estimate (if * generation. 6-9 ==> don't try fast floating-point estimate (if
* applicable). * applicable).
* *
* Values of mode other than 0-9 are treated as mode 0. * Values of mode other than 0-9 are treated as mode 0.
* *
* Sufficient space is allocated to the return value to hold the suppressed * Sufficient space is allocated to the return value to hold the suppressed
* trailing zeros. */ * trailing zeros. */
@ -989,11 +1046,14 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
#endif #endif
"NaN"; "NaN";
if (rve) if (rve)
*rve = {
*rve =
#ifdef IEEE_Arith #ifdef IEEE_Arith
s[3] ? s + 8 : s[3] ? s + 8 :
#endif #endif
s + 3; s + 3;
}
return s; return s;
} }
#endif #endif
@ -1002,7 +1062,10 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
*decpt = 1; *decpt = 1;
s = "0"; s = "0";
if (rve) if (rve)
*rve = s + 1; {
*rve = s + 1;
}
return s; return s;
} }
@ -1017,10 +1080,10 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
* log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) log10(d) = * log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) log10(d) =
* (i-Bias)*log(2)/log(10) + log10(d2) This suggests computing an * (i-Bias)*log(2)/log(10) + log10(d2) This suggests computing an
* approximation k to log10(d) by k = (i - Bias)*0.301029995663981 + ( * approximation k to log10(d) by k = (i - Bias)*0.301029995663981 + (
* (d2-1.5)*0.289529654602168 + 0.176091259055681 ); We want k to be too * (d2-1.5)*0.289529654602168 + 0.176091259055681 ); We want k to be too
* large rather than too small. The error in the first-order Taylor * large rather than too small. The error in the first-order Taylor
* series approximation is in our favor, so we just round up the constant * series approximation is in our favor, so we just round up the constant
* enough to compensate for any error in the multiplication of (i - Bias) * enough to compensate for any error in the multiplication of (i - Bias)
* by 0.301029995663981; since |i - Bias| <= 1077, and 1077 * 0.30103 * * by 0.301029995663981; since |i - Bias| <= 1077, and 1077 * 0.30103 *
* 2^-52 ~=~ 7.2e-14, adding 1e-13 to the constant term more than * 2^-52 ~=~ 7.2e-14, adding 1e-13 to the constant term more than
* suffices. Hence we adjust the constant term to 0.1760912590558. (We * suffices. Hence we adjust the constant term to 0.1760912590558. (We
@ -1049,6 +1112,7 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
{ {
k--; /* want k = floor(ds) */ k--; /* want k = floor(ds) */
} }
k_check = 1; k_check = 1;
if (k >= 0 && k <= Ten_pmax) if (k >= 0 && k <= Ten_pmax)
@ -1226,11 +1290,20 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
d -= L; d -= L;
*s++ = '0' + (int)L; *s++ = '0' + (int)L;
if (d < eps) if (d < eps)
goto ret1; {
goto ret1;
}
if (1. - d < eps) if (1. - d < eps)
goto bump_up; {
goto bump_up;
}
if (++i >= ilim) if (++i >= ilim)
break; {
break;
}
eps *= 10.; eps *= 10.;
d *= 10.; d *= 10.;
} }
@ -1239,7 +1312,7 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
{ {
#endif #endif
/* Generate ilim digits, then fix them up. */ /* Generate ilim digits, then fix them up. */
eps *= tens[ilim - 1]; eps *= tens[ilim - 1];
for (i = 1;; i++, d *= 10.) for (i = 1;; i++, d *= 10.)
{ {
@ -1249,13 +1322,16 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
if (i == ilim) if (i == ilim)
{ {
if (d > 0.5 + eps) if (d > 0.5 + eps)
goto bump_up; {
goto bump_up;
}
else if (d < 0.5 - eps) else if (d < 0.5 - eps)
{ {
while (*--s == '0'); while (*--s == '0');
s++; s++;
goto ret1; goto ret1;
} }
break; break;
} }
} }
@ -1280,7 +1356,10 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
{ {
S = mhi = 0; S = mhi = 0;
if (ilim < 0 || d <= 5 * ds) if (ilim < 0 || d <= 5 * ds)
goto no_digits; {
goto no_digits;
}
goto one_digit; goto one_digit;
} }
@ -1310,10 +1389,12 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
*s = '0'; *s = '0';
break; break;
} }
++*s++; ++*s++;
} }
break; break;
} }
if (!(d *= 10.)) if (!(d *= 10.))
{ {
break; break;
@ -1343,6 +1424,7 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
b5 += j; b5 += j;
m5 = 0; m5 = 0;
} }
if ((i = ilim) < 0) if ((i = ilim) < 0)
{ {
m2 -= i; m2 -= i;
@ -1374,8 +1456,11 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
Bfree(b); Bfree(b);
b = b1; b = b1;
} }
if ((j = b5 - m5)) if ((j = b5 - m5))
b = pow5mult(b, j); {
b = pow5mult(b, j);
}
} }
else else
{ {
@ -1471,10 +1556,12 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
if (ilim < 0 || cmp(b, S = multadd(S, 5, 0)) <= 0) if (ilim < 0 || cmp(b, S = multadd(S, 5, 0)) <= 0)
{ {
/* no digits, fcvt style */ /* no digits, fcvt style */
no_digits: no_digits:
k = -1 - ndigits; k = -1 - ndigits;
goto ret; goto ret;
} }
one_digit: one_digit:
*s++ = '1'; *s++ = '1';
k++; k++;
@ -1603,6 +1690,7 @@ char *__dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
*s++ = '1'; *s++ = '1';
goto ret; goto ret;
} }
++*s++; ++*s++;
} }
else else
@ -1625,7 +1713,7 @@ ret:
ret1: ret1:
Bfree(b); Bfree(b);
if (s == s0) if (s == s0)
{ /* don't return empty string */ { /* Don't return empty string */
*s++ = '0'; *s++ = '0';
k = 0; k = 0;
} }

View File

@ -160,7 +160,7 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
/* Special handling for NaN and Infinity */ /* Special handling for NaN and Infinity */
if (isnan(value)) if (isnan(value))
{ {
lib_dtoa_string(obj, "NaN"); lib_dtoa_string(obj, "NaN");
return; return;
@ -168,7 +168,7 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
if (isinf(value)) if (isinf(value))
{ {
if (value < 0.0d) if (value < 0.0)
{ {
obj->put(obj, '-'); obj->put(obj, '-');
} }
@ -340,4 +340,3 @@ static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec,
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/