Changeset 33c2952 in mainline for uspace/lib/c


Ignore:
Timestamp:
2012-11-07T21:00:02Z (13 years ago)
Author:
Adam Hraska <adam.hraska+hos@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
dcb0751
Parents:
fc89e32 (diff), 94795812 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merged with mainline.

Location:
uspace/lib/c
Files:
17 added
44 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/Makefile

    rfc89e32 r33c2952  
    7171        generic/device/hw_res_parsed.c \
    7272        generic/device/char_dev.c \
     73        generic/device/clock_dev.c \
     74        generic/device/battery_dev.c \
    7375        generic/device/graph_dev.c \
    7476        generic/device/nic.c \
    7577        generic/device/pci.c \
    7678        generic/device/ahci.c \
     79        generic/dlfcn.c \
    7780        generic/elf/elf_load.c \
    7881        generic/event.c \
     
    101104        generic/io/printf.c \
    102105        generic/io/log.c \
     106        generic/io/logctl.c \
    103107        generic/io/klog.c \
    104108        generic/io/snprintf.c \
     
    106110        generic/io/vsnprintf.c \
    107111        generic/io/printf_core.c \
     112        generic/io/con_srv.c \
    108113        generic/io/console.c \
    109114        generic/io/visualizer.c \
     
    111116        generic/iplink.c \
    112117        generic/iplink_srv.c \
     118        generic/ieee_double.c \
     119        generic/power_of_ten.c \
     120        generic/double_to_str.c \
    113121        generic/malloc.c \
    114122        generic/sysinfo.c \
     
    140148ifeq ($(CONFIG_RTLD),y)
    141149        GENERIC_SOURCES += \
    142                 generic/dlfcn.c \
    143150                generic/rtld/rtld.c \
    144151                generic/rtld/dynamic.c \
  • uspace/lib/c/arch/abs32le/_link.ld.in

    rfc89e32 r33c2952  
    1515#ifdef LOADER
    1616        . = 0x70001000 + SIZEOF_HEADERS;
    17        
    18         .interp : {
    19                 *(.interp);
    20         } :interp :text
    2117#else
    2218        . = 0x1000 + SIZEOF_HEADERS;
    2319#endif
    24        
    25         /* Make sure the code is aligned reasonably */
    26         . = ALIGN(., 16);
    2720       
    2821        .text : {
     
    3023                *(.rodata .rodata.*);
    3124        } :text
     25       
     26#ifdef LOADER
     27        .interp : {
     28                *(.interp);
     29        } :interp :text
     30#endif
    3231       
    3332        . = . + 0x1000;
  • uspace/lib/c/arch/abs32le/include/types.h

    rfc89e32 r33c2952  
    4747
    4848typedef uint32_t sysarg_t;
     49typedef int32_t native_t;
    4950
    5051typedef int32_t ssize_t;
  • uspace/lib/c/arch/amd64/_link.ld.in

    rfc89e32 r33c2952  
    1616#ifdef LOADER
    1717        . = 0x70001000 + SIZEOF_HEADERS;
    18        
    19         .interp : {
    20                 *(.interp);
    21         } :interp :text
    2218#else
    2319        . = 0x1000 + SIZEOF_HEADERS;
    2420#endif
    25        
    26         /* Make sure the code is aligned reasonably */
    27         . = ALIGN(., 16);
    2821       
    2922        .init : {
     
    3528                *(.rodata .rodata.*);
    3629        } :text
     30       
     31#ifdef LOADER
     32        .interp : {
     33                *(.interp);
     34        } :interp :text
     35#endif
    3736       
    3837        . = . + 0x1000;
  • uspace/lib/c/arch/amd64/include/types.h

    rfc89e32 r33c2952  
    4747
    4848typedef uint64_t sysarg_t;
     49typedef int64_t native_t;
    4950
    5051typedef int64_t ssize_t;
  • uspace/lib/c/arch/arm32/Makefile.common

    rfc89e32 r33c2952  
    2828#
    2929
    30 GCC_CFLAGS += -ffixed-r9 -mtp=soft -fno-omit-frame-pointer -march=armv4
     30BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
     31GCC_CFLAGS += -ffixed-r9 -mtp=soft -fno-omit-frame-pointer -march=armv4 -mapcs-frame
    3132
    3233ENDIANESS = LE
  • uspace/lib/c/arch/arm32/_link.ld.in

    rfc89e32 r33c2952  
    1515#ifdef LOADER
    1616        . = 0x70001000 + SIZEOF_HEADERS;
    17        
    18         .interp : {
    19                 *(.interp);
    20         } :interp :text
    2117#else
    2218        . = 0x1000 + SIZEOF_HEADERS;
    2319#endif
    24        
    25         /* Make sure the code is aligned reasonably */
    26         . = ALIGN(., 8);
    2720       
    2821        .init : {
     
    3427                *(.rodata .rodata.*);
    3528        } :text
     29       
     30#ifdef LOADER
     31        .interp : {
     32                *(.interp);
     33        } :interp :text
     34#endif
    3635       
    3736        . = . + 0x1000;
  • uspace/lib/c/arch/arm32/include/types.h

    rfc89e32 r33c2952  
    4848
    4949typedef uint32_t sysarg_t;
     50typedef int32_t native_t;
    5051
    5152typedef int32_t ssize_t;
  • uspace/lib/c/arch/ia32/_link.ld.in

    rfc89e32 r33c2952  
    2424        . = 0x1000 + SIZEOF_HEADERS;
    2525#endif
    26        
    27 #if defined(LOADER) || defined(DLEXE)
    28         .interp : {
    29                 *(.interp);
    30         } :interp :text
    31 #endif
    32        
    33         /* Make sure the code is aligned reasonably */
    34         . = ALIGN(., 16);
    3526       
    3627        .init : {
     
    7162        } :text
    7263#endif
     64       
     65#if defined(LOADER) || defined(DLEXE)
     66        .interp : {
     67                *(.interp);
     68        } :interp :text
     69#endif
     70       
    7371        . = . + 0x1000;
    7472       
  • uspace/lib/c/arch/ia32/include/types.h

    rfc89e32 r33c2952  
    4747
    4848typedef uint32_t sysarg_t;
     49typedef int32_t native_t;
    4950
    5051typedef int32_t ssize_t;
  • uspace/lib/c/arch/ia64/_link.ld.in

    rfc89e32 r33c2952  
    1515#ifdef LOADER
    1616        . = 0x800000000 + SIZEOF_HEADERS;
    17        
    18         .interp : {
    19                 *(.interp);
    20         } :interp :text
    2117#else
    2218        . = 0x4000 + SIZEOF_HEADERS;
    2319#endif
    2420       
    25         /* Make sure the code is aligned reasonably */
     21        /* Workaround proper alignment of the .init section */
    2622        . = ALIGN(., 16);
    2723       
     
    3430                *(.rodata .rodata.*);
    3531        } :text
     32       
     33#ifdef LOADER
     34        .interp : {
     35                *(.interp);
     36        } :interp :text
     37#endif
    3638       
    3739        . = . + 0x4000;
  • uspace/lib/c/arch/ia64/include/types.h

    rfc89e32 r33c2952  
    5757
    5858typedef uint64_t sysarg_t;
     59typedef int64_t native_t;
    5960
    6061typedef int64_t ssize_t;
  • uspace/lib/c/arch/mips32/Makefile.common

    rfc89e32 r33c2952  
    2828
    2929GCC_CFLAGS += -msoft-float -mips3 -mabi=32
     30BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
    3031
    3132ENDIANESS = LE
  • uspace/lib/c/arch/mips32/_link.ld.in

    rfc89e32 r33c2952  
    1515#ifdef LOADER
    1616        . = 0x70004000 + SIZEOF_HEADERS;
    17        
    18         .interp : {
    19                 *(.interp);
    20         } :interp :text
    2117#else
    2218        . = 0x4000 + SIZEOF_HEADERS;
    2319#endif
    24        
    25         /* Make sure the code is aligned reasonably */
    26         . = ALIGN(., 16);
    2720       
    2821        .init : {
     
    3427                *(.rodata .rodata.*);
    3528        } :text
     29       
     30#ifdef LOADER
     31        .interp : {
     32                *(.interp);
     33        } :interp :text
     34#endif
    3635       
    3736        . = . + 0x4000;
  • uspace/lib/c/arch/mips32/include/types.h

    rfc89e32 r33c2952  
    4848
    4949typedef uint32_t sysarg_t;
     50typedef int32_t native_t;
    5051
    5152typedef int32_t ssize_t;
  • uspace/lib/c/arch/mips32eb/Makefile.common

    rfc89e32 r33c2952  
    2828
    2929GCC_CFLAGS += -msoft-float -mips3 -mabi=32
     30BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
    3031
    3132ENDIANESS = BE
  • uspace/lib/c/arch/mips64/Makefile.common

    rfc89e32 r33c2952  
    2828
    2929GCC_CFLAGS += -msoft-float -mips3 -mabi=64
     30BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
    3031AFLAGS = -64
    3132
  • uspace/lib/c/arch/mips64/_link.ld.in

    rfc89e32 r33c2952  
    1616#ifdef LOADER
    1717        . = 0x70004000 + SIZEOF_HEADERS;
    18        
    19         .interp : {
    20                 *(.interp);
    21         } :interp :text
    2218#else
    2319        . = 0x4000 + SIZEOF_HEADERS;
    2420#endif
    25        
    26         /* Make sure the code is aligned reasonably */
    27         . = ALIGN(., 16);
    2821       
    2922        .init : {
     
    3528                *(.rodata .rodata.*);
    3629        } :text
     30       
     31#ifdef LOADER
     32        .interp : {
     33                *(.interp);
     34        } :interp :text
     35#endif
    3736       
    3837        . = . + 0x4000;
  • uspace/lib/c/arch/mips64/include/types.h

    rfc89e32 r33c2952  
    4848
    4949typedef uint64_t sysarg_t;
     50typedef int64_t native_t;
    5051
    5152typedef int64_t ssize_t;
  • uspace/lib/c/arch/ppc32/Makefile.common

    rfc89e32 r33c2952  
    2828
    2929GCC_CFLAGS += -mcpu=powerpc -msoft-float -m32
     30BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a
    3031AFLAGS = -a32
    3132
  • uspace/lib/c/arch/ppc32/_link.ld.in

    rfc89e32 r33c2952  
    1616#ifdef LOADER
    1717        . = 0x70001000 + SIZEOF_HEADERS;
    18        
    19         .interp : {
    20                 *(.interp);
    21         } :interp :text
    2218#else
    2319        . = 0x1000 + SIZEOF_HEADERS;
    2420#endif
    25        
    26         /* Make sure the code is aligned reasonably */
    27         . = ALIGN(., 4);
    2821       
    2922        .init : {
     
    3528                *(.rodata .rodata.*);
    3629        } :text
     30       
     31#ifdef LOADER
     32        .interp : {
     33                *(.interp);
     34        } :interp :text
     35#endif
    3736       
    3837        . = . + 0x1000;
  • uspace/lib/c/arch/ppc32/include/types.h

    rfc89e32 r33c2952  
    4747
    4848typedef uint32_t sysarg_t;
     49typedef int32_t native_t;
    4950
    5051typedef int32_t ssize_t;
  • uspace/lib/c/arch/sparc64/_link.ld.in

    rfc89e32 r33c2952  
    1515#ifdef LOADER
    1616        . = 0x70004000 + SIZEOF_HEADERS;
    17        
    18         .interp : {
    19                 *(.interp);
    20         } :interp :text
    2117#else
    2218        . = 0x4000 + SIZEOF_HEADERS;
    2319#endif
    24        
    25         /* Make sure the code is aligned reasonably */
    26         . = ALIGN(., 16);
    2720       
    2821        .init : {
     
    3427                *(.rodata .rodata.*);
    3528        } :text
     29       
     30#ifdef LOADER
     31        .interp : {
     32                *(.interp);
     33        } :interp :text
     34#endif
    3635       
    3736        . = . + 0x4000;
  • uspace/lib/c/arch/sparc64/include/types.h

    rfc89e32 r33c2952  
    4747
    4848typedef uint64_t sysarg_t;
     49typedef int64_t native_t;
    4950
    5051typedef int64_t ssize_t;
  • uspace/lib/c/generic/adt/hash_table.c

    rfc89e32 r33c2952  
    6262
    6363
    64 static size_t round_up_size(size_t size);
    65 static bool alloc_table(size_t bucket_cnt, list_t **pbuckets);
    66 static void clear_items(hash_table_t *h);
    67 static void resize(hash_table_t *h, size_t new_bucket_cnt);
    68 static void grow_if_needed(hash_table_t *h);
    69 static void shrink_if_needed(hash_table_t *h);
     64static size_t round_up_size(size_t);
     65static bool alloc_table(size_t, list_t **);
     66static void clear_items(hash_table_t *);
     67static void resize(hash_table_t *, size_t);
     68static void grow_if_needed(hash_table_t *);
     69static void shrink_if_needed(hash_table_t *);
    7070
    7171/* Dummy do nothing callback to invoke in place of remove_callback == NULL. */
  • uspace/lib/c/generic/async.c

    rfc89e32 r33c2952  
    416416        .key_hash = client_key_hash,
    417417        .key_equal = client_key_equal,
    418         .equal = 0,
    419         .remove_callback = 0
     418        .equal = NULL,
     419        .remove_callback = NULL
    420420};
    421421
     
    452452        .key_hash = conn_key_hash,
    453453        .key_equal = conn_key_equal,
    454         .equal = 0,
    455         .remove_callback = 0
     454        .equal = NULL,
     455        .remove_callback = NULL
    456456};
    457457
     
    628628       
    629629        if (usecs) {
    630                 gettimeofday(&conn->wdata.to_event.expires, NULL);
     630                getuptime(&conn->wdata.to_event.expires);
    631631                tv_add(&conn->wdata.to_event.expires, usecs);
    632632        } else
     
    947947{
    948948        struct timeval tv;
    949         gettimeofday(&tv, NULL);
     949        getuptime(&tv);
    950950       
    951951        futex_down(&async_futex);
     
    10041004                       
    10051005                        struct timeval tv;
    1006                         gettimeofday(&tv, NULL);
     1006                        getuptime(&tv);
    10071007                       
    10081008                        if (tv_gteq(&tv, &waiter->to_event.expires)) {
     
    13091309                timeout = 0;
    13101310
    1311         gettimeofday(&msg->wdata.to_event.expires, NULL);
     1311        getuptime(&msg->wdata.to_event.expires);
    13121312        tv_add(&msg->wdata.to_event.expires, timeout);
    13131313       
     
    13911391        msg->wdata.fid = fibril_get_id();
    13921392       
    1393         gettimeofday(&msg->wdata.to_event.expires, NULL);
     1393        getuptime(&msg->wdata.to_event.expires);
    13941394        tv_add(&msg->wdata.to_event.expires, timeout);
    13951395       
  • uspace/lib/c/generic/dlfcn.c

    rfc89e32 r33c2952  
    3838#include <stdlib.h>
    3939#include <dlfcn.h>
     40
     41#ifdef CONFIG_RTLD
    4042
    4143#include <rtld/module.h>
     
    8789}
    8890
     91#else /* CONFIG_RTLD not defined */
     92
     93void *dlopen(const char *path, int flag)
     94{
     95        return NULL;
     96}
     97
     98void *dlsym(void *mod, const char *sym_name)
     99{
     100        return NULL;
     101}
     102
     103#endif
     104
    89105/** @}
    90106 */
  • uspace/lib/c/generic/fibril_synch.c

    rfc89e32 r33c2952  
    379379        futex_down(&async_futex);
    380380        if (timeout) {
    381                 gettimeofday(&wdata.to_event.expires, NULL);
     381                getuptime(&wdata.to_event.expires);
    382382                tv_add(&wdata.to_event.expires, timeout);
    383383                async_insert_timeout(&wdata);
  • uspace/lib/c/generic/io/console.c

    rfc89e32 r33c2952  
    3838#include <async.h>
    3939#include <errno.h>
    40 #include <stdio.h>
    4140#include <malloc.h>
    4241#include <vfs/vfs_sess.h>
     
    126125{
    127126        async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
    128         async_req_1_0(exch, CONSOLE_CURSOR_VISIBILITY, (show != false));
     127        async_req_1_0(exch, CONSOLE_SET_CURSOR_VISIBILITY, (show != false));
    129128        async_exchange_end(exch);
    130129}
     
    151150{
    152151        async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
    153         async_req_2_0(exch, CONSOLE_GOTO, col, row);
     152        async_req_2_0(exch, CONSOLE_SET_POS, col, row);
    154153        async_exchange_end(exch);
    155154}
  • uspace/lib/c/generic/io/input.c

    rfc89e32 r33c2952  
    143143        x = IPC_GET_ARG1(*call);
    144144        y = IPC_GET_ARG2(*call);
    145         max_x = IPC_GET_ARG2(*call);
    146         max_y = IPC_GET_ARG3(*call);
     145        max_x = IPC_GET_ARG3(*call);
     146        max_y = IPC_GET_ARG4(*call);
    147147
    148148        rc = input->ev_ops->abs_move(input, x, y, max_x, max_y);
  • uspace/lib/c/generic/io/log.c

    rfc89e32 r33c2952  
    3838#include <stdlib.h>
    3939#include <stdio.h>
    40 
     40#include <async.h>
    4141#include <io/log.h>
    42 
    43 /** Serialization mutex for logging functions. */
    44 static FIBRIL_MUTEX_INITIALIZE(log_serializer);
    45 
    46 /** Current log level. */
    47 static log_level_t log_level;
    48 
    49 static FILE *log_stream;
    50 
     42#include <ipc/logger.h>
     43#include <ns.h>
     44
     45/** Id of the first log we create at logger. */
     46static sysarg_t default_log_id;
     47
     48/** Log messages are printed under this name. */
    5149static const char *log_prog_name;
    5250
    53 /** Prefixes for individual logging levels. */
     51/** Names of individual log levels. */
    5452static const char *log_level_names[] = {
    55         [LVL_FATAL] = "Fatal error",
    56         [LVL_ERROR] = "Error",
    57         [LVL_WARN] = "Warning",
    58         [LVL_NOTE] = "Note",
    59         [LVL_DEBUG] = "Debug",
    60         [LVL_DEBUG2] = "Debug2"
     53        "fatal",
     54        "error",
     55        "warn",
     56        "note",
     57        "debug",
     58        "debug2",
     59        NULL
    6160};
    6261
     62/** IPC session with the logger service. */
     63static async_sess_t *logger_session;
     64
     65/** Maximum length of a single log message (in bytes). */
     66#define MESSAGE_BUFFER_SIZE 4096
     67
     68/** Send formatted message to the logger service.
     69 *
     70 * @param session Initialized IPC session with the logger.
     71 * @param log Log to use.
     72 * @param level Verbosity level of the message.
     73 * @param message The actual message.
     74 * @return Error code of the conversion or EOK on success.
     75 */
     76static int logger_message(async_sess_t *session, log_t log, log_level_t level, char *message)
     77{
     78        async_exch_t *exchange = async_exchange_begin(session);
     79        if (exchange == NULL) {
     80                return ENOMEM;
     81        }
     82        if (log == LOG_DEFAULT)
     83                log = default_log_id;
     84
     85        // FIXME: remove when all USB drivers use libc logging explicitly
     86        str_rtrim(message, '\n');
     87
     88        aid_t reg_msg = async_send_2(exchange, LOGGER_WRITER_MESSAGE,
     89            log, level, NULL);
     90        int rc = async_data_write_start(exchange, message, str_size(message));
     91        sysarg_t reg_msg_rc;
     92        async_wait_for(reg_msg, &reg_msg_rc);
     93
     94        async_exchange_end(exchange);
     95
     96        /*
     97         * Getting ENAK means no-one wants our message. That is not an
     98         * error at all.
     99         */
     100        if (rc == ENAK)
     101                rc = EOK;
     102
     103        if (rc != EOK) {
     104                return rc;
     105        }
     106
     107        return reg_msg_rc;
     108}
     109
     110/** Get name of the log level.
     111 *
     112 * @param level The log level.
     113 * @return String name or "unknown".
     114 */
     115const char *log_level_str(log_level_t level)
     116{
     117        if (level >= LVL_LIMIT)
     118                return "unknown";
     119        else
     120                return log_level_names[level];
     121}
     122
     123/** Convert log level name to the enum.
     124 *
     125 * @param[in] name Log level name or log level number.
     126 * @param[out] level_out Where to store the result (set to NULL to ignore).
     127 * @return Error code of the conversion or EOK on success.
     128 */
     129int log_level_from_str(const char *name, log_level_t *level_out)
     130{
     131        log_level_t level = LVL_FATAL;
     132
     133        while (log_level_names[level] != NULL) {
     134                if (str_cmp(name, log_level_names[level]) == 0) {
     135                        if (level_out != NULL)
     136                                *level_out = level;
     137                        return EOK;
     138                }
     139                level++;
     140        }
     141
     142        /* Maybe user specified number directly. */
     143        char *end_ptr;
     144        int level_int = strtol(name, &end_ptr, 0);
     145        if ((end_ptr == name) || (str_length(end_ptr) != 0))
     146                return EINVAL;
     147        if (level_int < 0)
     148                return ERANGE;
     149        if (level_int >= (int) LVL_LIMIT)
     150                return ERANGE;
     151
     152        if (level_out != NULL)
     153                *level_out = (log_level_t) level_int;
     154
     155        return EOK;
     156}
     157
    63158/** Initialize the logging system.
    64159 *
    65  * @param prog_name     Program name, will be printed as part of message
    66  * @param level         Minimum message level to print
    67  */
    68 int log_init(const char *prog_name, log_level_t level)
    69 {
    70         assert(level < LVL_LIMIT);
    71         log_level = level;
    72 
    73         log_stream = stdout;
     160 * @param prog_name Program name, will be printed as part of message
     161 */
     162int log_init(const char *prog_name)
     163{
    74164        log_prog_name = str_dup(prog_name);
    75165        if (log_prog_name == NULL)
    76166                return ENOMEM;
    77167
     168        logger_session = service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_LOGGER, LOGGER_INTERFACE_WRITER, 0);
     169        if (logger_session == NULL) {
     170                return ENOMEM;
     171        }
     172
     173        default_log_id = log_create(prog_name, LOG_NO_PARENT);
     174
    78175        return EOK;
    79176}
    80177
     178/** Create a new (sub-) log.
     179 *
     180 * This function always returns a valid log_t. In case of errors,
     181 * @c parent is returned and errors are silently ignored.
     182 *
     183 * @param name Log name under which message will be reported (appended to parents name).
     184 * @param parent Parent log.
     185 * @return Opaque identifier of the newly created log.
     186 */
     187log_t log_create(const char *name, log_t parent)
     188{
     189        async_exch_t *exchange = async_exchange_begin(logger_session);
     190        if (exchange == NULL)
     191                return parent;
     192
     193        if (parent == LOG_DEFAULT)
     194                parent = default_log_id;
     195
     196        ipc_call_t answer;
     197        aid_t reg_msg = async_send_1(exchange, LOGGER_WRITER_CREATE_LOG,
     198            parent, &answer);
     199        int rc = async_data_write_start(exchange, name, str_size(name));
     200        sysarg_t reg_msg_rc;
     201        async_wait_for(reg_msg, &reg_msg_rc);
     202
     203        async_exchange_end(exchange);
     204
     205        if ((rc != EOK) || (reg_msg_rc != EOK))
     206                return parent;
     207
     208        return IPC_GET_ARG1(answer);
     209}
     210
    81211/** Write an entry to the log.
    82212 *
    83  * @param level         Message verbosity level. Message is only printed
    84  *                      if verbosity is less than or equal to current
    85  *                      reporting level.
    86  * @param fmt           Format string (no traling newline).
    87  */
    88 void log_msg(log_level_t level, const char *fmt, ...)
     213 * The message is printed only if the verbosity level is less than or
     214 * equal to currently set reporting level of the log.
     215 *
     216 * @param ctx Log to use (use LOG_DEFAULT if you have no idea what it means).
     217 * @param level Severity level of the message.
     218 * @param fmt Format string in printf-like format (without trailing newline).
     219 */
     220void log_msg(log_t ctx, log_level_t level, const char *fmt, ...)
    89221{
    90222        va_list args;
    91223
    92224        va_start(args, fmt);
    93         log_msgv(level, fmt, args);
     225        log_msgv(ctx, level, fmt, args);
    94226        va_end(args);
    95227}
     
    97229/** Write an entry to the log (va_list variant).
    98230 *
    99  * @param level         Message verbosity level. Message is only printed
    100  *                      if verbosity is less than or equal to current
    101  *                      reporting level.
    102  * @param fmt           Format string (no trailing newline)
    103  */
    104 void log_msgv(log_level_t level, const char *fmt, va_list args)
     231 * @param ctx Log to use (use LOG_DEFAULT if you have no idea what it means).
     232 * @param level Severity level of the message.
     233 * @param fmt Format string in printf-like format (without trailing newline).
     234 * @param args Arguments.
     235 */
     236void log_msgv(log_t ctx, log_level_t level, const char *fmt, va_list args)
    105237{
    106238        assert(level < LVL_LIMIT);
    107239
    108         /* Higher number means higher verbosity. */
    109         if (level <= log_level) {
    110                 fibril_mutex_lock(&log_serializer);
    111 
    112                 fprintf(log_stream, "%s: %s: ", log_prog_name,
    113                     log_level_names[level]);
    114                 vfprintf(log_stream, fmt, args);
    115                 fputc('\n', log_stream);
    116                 fflush(log_stream);
    117 
    118                 fibril_mutex_unlock(&log_serializer);
    119         }
     240        char *message_buffer = malloc(MESSAGE_BUFFER_SIZE);
     241        if (message_buffer == NULL)
     242                return;
     243
     244        vsnprintf(message_buffer, MESSAGE_BUFFER_SIZE, fmt, args);
     245        logger_message(logger_session, ctx, level, message_buffer);
     246        free(message_buffer);
    120247}
    121248
  • uspace/lib/c/generic/io/output.c

    rfc89e32 r33c2952  
    3737#include <as.h>
    3838#include <ipc/output.h>
     39#include <io/concaps.h>
    3940#include <io/output.h>
    4041
  • uspace/lib/c/generic/io/printf_core.c

    rfc89e32 r33c2952  
    4242#include <ctype.h>
    4343#include <str.h>
     44#include <double_to_str.h>
     45#include <ieee_double.h>
     46#include <assert.h>
     47#include <macros.h>
     48
    4449
    4550/** show prefixes 0x or 0 */
    4651#define __PRINTF_FLAG_PREFIX       0x00000001
    4752
     53/** show the decimal point even if no fractional digits present */
     54#define __PRINTF_FLAG_DECIMALPT    0x00000001
     55
    4856/** signed / unsigned number */
    4957#define __PRINTF_FLAG_SIGNED       0x00000002
     
    6674/** number has - sign */
    6775#define __PRINTF_FLAG_NEGATIVE     0x00000100
     76
     77/** don't print trailing zeros in the fractional part */
     78#define __PRINTF_FLAG_NOFRACZEROS  0x00000200
     79
    6880
    6981/**
     
    110122static const char invalch = U_SPECIAL;
    111123
     124
     125
     126/** Unformatted double number string representation. */
     127typedef struct {
     128        /** Buffer with len digits, no sign or leading zeros. */
     129        char *str;
     130        /** Number of digits in str. */
     131        int len;
     132        /** Decimal exponent, ie number = str * 10^dec_exp */
     133        int dec_exp;
     134        /** True if negative. */
     135        bool neg;
     136} double_str_t;
     137
     138
     139
     140/** Returns the sign character or 0 if no sign should be printed. */
     141static int get_sign_char(bool negative, uint32_t flags)
     142{
     143        if (negative) {
     144                return '-';
     145        } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
     146                return '+';
     147        } else if (flags & __PRINTF_FLAG_SPACESIGN) {
     148                return ' ';
     149        } else {
     150                return 0;
     151        }
     152}
     153
     154/** Prints count times character ch. */
     155static int print_padding(char ch, int count, printf_spec_t *ps)
     156{
     157        for (int i = 0; i < count; ++i) {
     158                if (ps->str_write(&ch, 1, ps->data) < 0) {
     159                        return -1;
     160                }
     161        }
     162
     163        return count;
     164}
     165
     166
    112167/** Print one or more characters without adding newline.
    113168 *
     
    281336                return printf_putstr(nullstr, ps);
    282337       
    283         /* Print leading spaces. */
    284338        size_t strw = str_length(str);
     339
     340        /* Precision unspecified - print everything. */
    285341        if ((precision == 0) || (precision > strw))
    286342                precision = strw;
     
    329385                return printf_putstr(nullstr, ps);
    330386       
    331         /* Print leading spaces. */
    332387        size_t strw = wstr_length(str);
     388
     389        /* Precision not specified - print everything. */
    333390        if ((precision == 0) || (precision > strw))
    334391                precision = strw;
     
    377434    uint32_t flags, printf_spec_t *ps)
    378435{
     436        /* Precision not specified. */
     437        if (precision < 0) {
     438                precision = 0;
     439        }
     440       
    379441        const char *digits;
    380442        if (flags & __PRINTF_FLAG_BIGCHARS)
     
    525587       
    526588        return ((int) counter);
     589}
     590
     591/** Prints a special double (ie NaN, infinity) padded to width characters. */
     592static int print_special(ieee_double_t val, int width, uint32_t flags,
     593        printf_spec_t *ps)
     594{
     595        assert(val.is_special);
     596
     597        char sign = get_sign_char(val.is_negative, flags);
     598
     599        const int str_len = 3;
     600        const char *str;
     601       
     602        if (flags & __PRINTF_FLAG_BIGCHARS) {
     603                str = val.is_infinity ? "INF" : "NAN";
     604        } else {
     605                str = val.is_infinity ? "inf" : "nan";
     606        }
     607
     608        int padding_len = max(0, width - ((sign ? 1 : 0) + str_len));
     609
     610        int counter = 0;
     611        int ret;
     612
     613        /* Leading padding. */
     614        if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
     615                if ((ret = print_padding(' ', padding_len, ps)) < 0)
     616                        return -1;
     617
     618                counter += ret;
     619        }
     620
     621        if (sign) {
     622                if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
     623                        return -1;
     624               
     625                counter += ret;
     626        }
     627
     628        if ((ret = ps->str_write(str, str_len, ps->data)) < 0)
     629                return -1;
     630       
     631        counter += ret;
     632
     633
     634        /* Trailing padding. */
     635        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     636                if ((ret = print_padding(' ', padding_len, ps)) < 0)
     637                        return -1;
     638
     639                counter += ret;
     640        }
     641
     642        return counter;
     643}
     644
     645/** Trims trailing zeros but leaves a single "0" intact. */
     646static void fp_trim_trailing_zeros(char *buf, int *len, int *dec_exp)
     647{
     648        /* Cut the zero off by adjusting the exponent. */
     649        while (2 <= *len && '0' == buf[*len - 1]) {
     650                --*len;
     651                ++*dec_exp;
     652        }
     653}
     654
     655/** Textually round up the last digit thereby eliminating it. */
     656static void fp_round_up(char *buf, int *len, int *dec_exp)
     657{
     658        assert(1 <= *len);
     659
     660        char *last_digit = &buf[*len - 1];
     661
     662        int carry = ('5' <= *last_digit);
     663
     664        /* Cut the digit off by adjusting the exponent. */
     665        --*len;
     666        ++*dec_exp;
     667        --last_digit;
     668
     669        if (carry) {
     670                /* Skip all the digits to cut off/round to zero. */
     671                while (buf <= last_digit && '9' == *last_digit) {
     672                        --last_digit;
     673                }
     674
     675                /* last_digit points to the last digit to round but not '9' */
     676                if (buf <= last_digit) {
     677                        *last_digit += 1;
     678                        int new_len = last_digit - buf + 1;
     679                        *dec_exp += *len - new_len;
     680                        *len = new_len;
     681                } else {
     682                        /* All len digits rounded to 0. */
     683                        buf[0] = '1';
     684                        *dec_exp += *len;
     685                        *len = 1;
     686                }
     687        } else {
     688                /* The only digit was rounded to 0. */
     689                if (last_digit < buf) {
     690                        buf[0] = '0';
     691                        *dec_exp = 0;
     692                        *len = 1;
     693                }
     694        }
     695}
     696
     697
     698/** Format and print the double string repressentation according
     699 *  to the %f specifier.
     700 */
     701static int print_double_str_fixed(double_str_t *val_str, int precision, int width,
     702        uint32_t flags, printf_spec_t *ps)
     703{
     704        int len = val_str->len;
     705        char *buf = val_str->str;
     706        int dec_exp = val_str->dec_exp;
     707
     708        assert(0 < len);
     709        assert(0 <= precision);
     710        assert(0 <= dec_exp || -dec_exp <= precision);
     711
     712        /* Number of integral digits to print (at least leading zero). */
     713        int int_len = max(1, len + dec_exp);
     714
     715        char sign = get_sign_char(val_str->neg, flags);
     716
     717        /* Fractional portion lengths. */
     718        int last_frac_signif_pos = max(0, -dec_exp);
     719        int leading_frac_zeros = max(0, last_frac_signif_pos - len);
     720        int signif_frac_figs = min(last_frac_signif_pos, len);
     721        int trailing_frac_zeros = precision - last_frac_signif_pos;
     722        char *buf_frac = buf + len - signif_frac_figs;
     723
     724        if (flags & __PRINTF_FLAG_NOFRACZEROS) {
     725                trailing_frac_zeros = 0;
     726        }
     727
     728        int frac_len = leading_frac_zeros + signif_frac_figs + trailing_frac_zeros;
     729
     730        bool has_decimal_pt = (0 < frac_len) || (flags & __PRINTF_FLAG_DECIMALPT);
     731
     732        /* Number of non-padding chars to print. */
     733        int num_len = (sign ? 1 : 0) + int_len + (has_decimal_pt ? 1 : 0) + frac_len;
     734
     735        int padding_len = max(0, width - num_len);
     736        int ret = 0;
     737        int counter = 0;
     738
     739        /* Leading padding and sign. */
     740
     741        if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) {
     742                if ((ret = print_padding(' ', padding_len, ps)) < 0)
     743                        return -1;
     744
     745                counter += ret;
     746        }
     747
     748        if (sign) {
     749                if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
     750                        return -1;
     751               
     752                counter += ret;
     753        }
     754
     755        if (flags & __PRINTF_FLAG_ZEROPADDED) {
     756                if ((ret = print_padding('0', padding_len, ps)) < 0)
     757                        return -1;
     758
     759                counter += ret;
     760        }
     761
     762        /* Print the intergral part of the buffer. */
     763
     764        int buf_int_len = min(len, len + dec_exp);
     765
     766        if (0 < buf_int_len) {
     767                if ((ret = ps->str_write(buf, buf_int_len, ps->data)) < 0)
     768                        return -1;
     769
     770                counter += ret;
     771
     772                /* Print trailing zeros of the integral part of the number. */
     773                if ((ret = print_padding('0', int_len - buf_int_len, ps)) < 0)
     774                        return -1;
     775        } else {
     776                /* Single leading integer 0. */
     777                char ch = '0';
     778                if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
     779                        return -1;
     780        }
     781
     782        counter += ret;
     783       
     784        /* Print the decimal point and the fractional part. */
     785        if (has_decimal_pt) {
     786                char ch = '.';
     787
     788                if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
     789                        return -1;
     790               
     791                counter += ret;
     792
     793                /* Print leading zeros of the fractional part of the number. */
     794                if ((ret = print_padding('0', leading_frac_zeros, ps)) < 0)
     795                        return -1;
     796
     797                counter += ret;
     798
     799                /* Print significant digits of the fractional part of the number. */
     800                if (0 < signif_frac_figs) {
     801                        if ((ret = ps->str_write(buf_frac, signif_frac_figs, ps->data)) < 0)
     802                                return -1;
     803
     804                        counter += ret;
     805                }
     806
     807                /* Print trailing zeros of the fractional part of the number. */
     808                if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0)
     809                        return -1;
     810
     811                counter += ret;
     812        }
     813
     814        /* Trailing padding. */
     815        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     816                if ((ret = print_padding(' ', padding_len, ps)) < 0)
     817                        return -1;
     818
     819                counter += ret;
     820        }
     821
     822        return counter;
     823}
     824
     825
     826/** Convert, format and print a double according to the %f specifier.
     827 *
     828 * @param g     Double to print.
     829 * @param precision Number of fractional digits to print. If 0 no
     830 *              decimal point will be printed unless the flag
     831 *              __PRINTF_FLAG_DECIMALPT is specified.
     832 * @param width Minimum number of characters to display. Pads
     833 *              with '0' or ' ' depending on the set flags;
     834 * @param flags Printf flags.
     835 * @param ps    Printing functions.
     836 *
     837 * @return The number of characters printed; negative on failure.
     838 */
     839static int print_double_fixed(double g, int precision, int width, uint32_t flags,
     840        printf_spec_t *ps)
     841{
     842        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     843                flags &= ~__PRINTF_FLAG_ZEROPADDED;
     844        }
     845
     846        if (flags & __PRINTF_FLAG_DECIMALPT) {
     847                flags &= ~__PRINTF_FLAG_NOFRACZEROS;
     848        }
     849
     850        ieee_double_t val = extract_ieee_double(g);
     851
     852        if (val.is_special) {
     853                return print_special(val, width, flags, ps);
     854        }
     855
     856        char buf[MAX_DOUBLE_STR_BUF_SIZE];
     857        const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
     858        double_str_t val_str;
     859
     860        val_str.str = buf;
     861        val_str.neg = val.is_negative;
     862
     863        if (0 <= precision) {
     864                /*
     865                 * Request one more digit so we can round the result. The last
     866                 * digit it returns may have an error of at most +/- 1.
     867                 */
     868                val_str.len = double_to_fixed_str(val, -1, precision + 1, buf, buf_size,
     869                        &val_str.dec_exp);
     870
     871                /*
     872                 * Round using the last digit to produce precision fractional digits.
     873                 * If less than precision+1 fractional digits were output the last
     874                 * digit is definitely inaccurate so also round to get rid of it.
     875                 */
     876                fp_round_up(buf, &val_str.len, &val_str.dec_exp);
     877
     878                /* Rounding could have introduced trailing zeros. */
     879                if (flags & __PRINTF_FLAG_NOFRACZEROS) {
     880                        fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
     881                }
     882        } else {
     883                /* Let the implementation figure out the proper precision. */
     884                val_str.len = double_to_short_str(val, buf, buf_size, &val_str.dec_exp);
     885               
     886                /* Precision needed for the last significant digit. */
     887                precision = max(0, -val_str.dec_exp);
     888        }
     889
     890        return print_double_str_fixed(&val_str, precision, width, flags, ps);
     891}
     892
     893/** Prints the decimal exponent part of a %e specifier formatted number. */
     894static int print_exponent(int exp_val, uint32_t flags, printf_spec_t *ps)
     895{
     896        int counter = 0;
     897        int ret;
     898
     899        char exp_ch = (flags & __PRINTF_FLAG_BIGCHARS) ? 'E' : 'e';
     900
     901        if ((ret = ps->str_write(&exp_ch, 1, ps->data)) < 0)
     902                return -1;
     903       
     904        counter += ret;
     905
     906        char exp_sign = (exp_val < 0) ? '-' : '+';
     907
     908        if ((ret = ps->str_write(&exp_sign, 1, ps->data)) < 0)
     909                return -1;
     910
     911        counter += ret;
     912
     913        /* Print the exponent. */
     914        exp_val = abs(exp_val);
     915       
     916        char exp_str[4] = { 0 };
     917
     918        exp_str[0] = '0' + exp_val / 100;
     919        exp_str[1] = '0' + (exp_val % 100) / 10 ;
     920        exp_str[2] = '0' + (exp_val % 10);
     921       
     922        int exp_len = (exp_str[0] == '0') ? 2 : 3;
     923        const char *exp_str_start = &exp_str[3] - exp_len;
     924
     925        if ((ret = ps->str_write(exp_str_start, exp_len, ps->data)) < 0)
     926                return -1;
     927
     928        counter += ret;
     929
     930        return counter;
     931}
     932
     933
     934/** Format and print the double string repressentation according
     935 *  to the %e specifier.
     936 */
     937static int print_double_str_scient(double_str_t *val_str, int precision,
     938        int width, uint32_t flags, printf_spec_t *ps)
     939{
     940        int len = val_str->len;
     941        int dec_exp = val_str->dec_exp;
     942        char *buf  = val_str->str;
     943
     944        assert(0 < len);
     945
     946        char sign = get_sign_char(val_str->neg, flags);
     947        bool has_decimal_pt = (0 < precision) || (flags & __PRINTF_FLAG_DECIMALPT);
     948        int dec_pt_len = has_decimal_pt ? 1 : 0;
     949
     950        /* Fractional part lengths. */
     951        int signif_frac_figs = len - 1;
     952        int trailing_frac_zeros = precision - signif_frac_figs;
     953
     954        if (flags & __PRINTF_FLAG_NOFRACZEROS) {
     955                trailing_frac_zeros = 0;
     956        }
     957
     958        int frac_len = signif_frac_figs + trailing_frac_zeros;
     959
     960        int exp_val = dec_exp + len - 1;
     961        /* Account for exponent sign and 'e'; minimum 2 digits. */
     962        int exp_len = 2 + (abs(exp_val) >= 100 ? 3 : 2);
     963
     964        /* Number of non-padding chars to print. */
     965        int num_len = (sign ? 1 : 0) + 1 + dec_pt_len + frac_len + exp_len;
     966
     967        int padding_len = max(0, width - num_len);
     968        int ret = 0;
     969        int counter = 0;
     970
     971        if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) {
     972                if ((ret = print_padding(' ', padding_len, ps)) < 0)
     973                        return -1;
     974
     975                counter += ret;
     976        }
     977
     978        if (sign) {
     979                if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
     980                        return -1;
     981               
     982                counter += ret;
     983        }
     984
     985        if (flags & __PRINTF_FLAG_ZEROPADDED) {
     986                if ((ret = print_padding('0', padding_len, ps)) < 0)
     987                        return -1;
     988
     989                counter += ret;
     990        }
     991
     992        /* Single leading integer. */
     993        if ((ret = ps->str_write(buf, 1, ps->data)) < 0)
     994                return -1;
     995
     996        counter += ret;
     997
     998        /* Print the decimal point and the fractional part. */
     999        if (has_decimal_pt) {
     1000                char ch = '.';
     1001
     1002                if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
     1003                        return -1;
     1004               
     1005                counter += ret;
     1006
     1007                /* Print significant digits of the fractional part of the number. */
     1008                if (0 < signif_frac_figs) {
     1009                        if ((ret = ps->str_write(buf + 1, signif_frac_figs, ps->data)) < 0)
     1010                                return -1;
     1011
     1012                        counter += ret;
     1013                }
     1014
     1015                /* Print trailing zeros of the fractional part of the number. */
     1016                if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0)
     1017                        return -1;
     1018
     1019                counter += ret;
     1020        }
     1021
     1022        /* Print the exponent. */
     1023        if ((ret = print_exponent(exp_val, flags, ps)) < 0)
     1024                return -1;
     1025
     1026        counter += ret;
     1027
     1028        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     1029                if ((ret = print_padding(' ', padding_len, ps)) < 0)
     1030                        return -1;
     1031
     1032                counter += ret;
     1033        }
     1034
     1035        return counter;
     1036}
     1037
     1038
     1039/** Convert, format and print a double according to the %e specifier.
     1040 *
     1041 * Note that if g is large, the output may be huge (3e100 prints
     1042 * with at least 100 digits).
     1043 *
     1044 * %e style: [-]d.dddde+dd
     1045 *  left-justified:  [-]d.dddde+dd[space_pad]
     1046 *  right-justified: [space_pad][-][zero_pad]d.dddde+dd
     1047 *
     1048 * @param g     Double to print.
     1049 * @param precision Number of fractional digits to print, ie
     1050 *              precision + 1 significant digits to display. If 0 no
     1051 *              decimal point will be printed unless the flag
     1052 *              __PRINTF_FLAG_DECIMALPT is specified. If negative
     1053 *              the shortest accurate number will be printed.
     1054 * @param width Minimum number of characters to display. Pads
     1055 *              with '0' or ' ' depending on the set flags;
     1056 * @param flags Printf flags.
     1057 * @param ps    Printing functions.
     1058 *
     1059 * @return The number of characters printed; negative on failure.
     1060 */
     1061static int print_double_scientific(double g, int precision, int width,
     1062        uint32_t flags, printf_spec_t *ps)
     1063{
     1064        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     1065                flags &= ~__PRINTF_FLAG_ZEROPADDED;
     1066        }
     1067
     1068        ieee_double_t val = extract_ieee_double(g);
     1069
     1070        if (val.is_special) {
     1071                return print_special(val, width, flags, ps);
     1072        }
     1073
     1074        char buf[MAX_DOUBLE_STR_BUF_SIZE];
     1075        const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
     1076        double_str_t val_str;
     1077
     1078        val_str.str = buf;
     1079        val_str.neg = val.is_negative;
     1080
     1081        if (0 <= precision) {
     1082                /*
     1083                 * Request one more digit (in addition to the leading integer)
     1084                 * so we can round the result. The last digit it returns may
     1085                 * have an error of at most +/- 1.
     1086                 */
     1087                val_str.len = double_to_fixed_str(val, precision + 2, -1, buf, buf_size,
     1088                        &val_str.dec_exp);
     1089
     1090                /*
     1091                 * Round the extra digit to produce precision+1 significant digits.
     1092                 * If less than precision+2 significant digits were returned the last
     1093                 * digit is definitely inaccurate so also round to get rid of it.
     1094                 */
     1095                fp_round_up(buf, &val_str.len, &val_str.dec_exp);
     1096
     1097                /* Rounding could have introduced trailing zeros. */
     1098                if (flags & __PRINTF_FLAG_NOFRACZEROS) {
     1099                        fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
     1100                }
     1101        } else {
     1102                /* Let the implementation figure out the proper precision. */
     1103                val_str.len = double_to_short_str(val, buf, buf_size, &val_str.dec_exp);
     1104               
     1105                /* Use all produced digits. */
     1106                precision = val_str.len - 1;
     1107        }
     1108
     1109        return print_double_str_scient(&val_str, precision, width, flags, ps);
     1110}
     1111
     1112
     1113/** Convert, format and print a double according to the %g specifier.
     1114 *
     1115 * %g style chooses between %f and %e.
     1116 *
     1117 * @param g     Double to print.
     1118 * @param precision Number of significant digits to display; excluding
     1119 *              any leading zeros from this count. If negative
     1120 *              the shortest accurate number will be printed.
     1121 * @param width Minimum number of characters to display. Pads
     1122 *              with '0' or ' ' depending on the set flags;
     1123 * @param flags Printf flags.
     1124 * @param ps    Printing functions.
     1125 *
     1126 * @return The number of characters printed; negative on failure.
     1127 */
     1128static int print_double_generic(double g, int precision, int width,
     1129        uint32_t flags, printf_spec_t *ps)
     1130{
     1131        ieee_double_t val = extract_ieee_double(g);
     1132
     1133        if (val.is_special) {
     1134                return print_special(val, width, flags, ps);
     1135        }
     1136
     1137        char buf[MAX_DOUBLE_STR_BUF_SIZE];
     1138        const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
     1139        int dec_exp;
     1140        int len;
     1141
     1142        /* Honor the user requested number of significant digits. */
     1143        if (0 <= precision) {
     1144                /*
     1145                 * Do a quick and dirty conversion of a single digit to determine
     1146                 * the decimal exponent.
     1147                 */
     1148                len = double_to_fixed_str(val, 1, -1, buf, buf_size, &dec_exp);
     1149                assert(0 < len);
     1150
     1151                precision = max(1, precision);
     1152
     1153                if (-4 <= dec_exp && dec_exp < precision) {
     1154                        precision = precision - (dec_exp + 1);
     1155                        return print_double_fixed(g, precision, width,
     1156                                flags | __PRINTF_FLAG_NOFRACZEROS, ps);
     1157                } else {
     1158                        --precision;
     1159                        return print_double_scientific(g, precision, width,
     1160                                flags | __PRINTF_FLAG_NOFRACZEROS, ps);
     1161                }
     1162        } else {
     1163                /* Convert to get the decimal exponent and digit count.*/
     1164                len = double_to_short_str(val, buf, buf_size, &dec_exp);
     1165                assert(0 < len);
     1166
     1167                if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     1168                        flags &= ~__PRINTF_FLAG_ZEROPADDED;
     1169                }
     1170
     1171                double_str_t val_str;
     1172                val_str.str = buf;
     1173                val_str.len = len;
     1174                val_str.neg = val.is_negative;
     1175                val_str.dec_exp = dec_exp;
     1176
     1177                int first_digit_pos = len + dec_exp;
     1178                int last_digit_pos = dec_exp;
     1179
     1180                /* The whole number (15 digits max) fits between dec places 15 .. -6 */
     1181                if (len <= 15 && -6 <= last_digit_pos && first_digit_pos <= 15) {
     1182                        /* Precision needed for the last significant digit. */
     1183                        precision = max(0, -val_str.dec_exp);
     1184                        return print_double_str_fixed(&val_str, precision, width, flags, ps);
     1185                } else {
     1186                        /* Use all produced digits. */
     1187                        precision = val_str.len - 1;
     1188                        return print_double_str_scient(&val_str, precision, width, flags, ps);
     1189                }
     1190        }
     1191}
     1192
     1193
     1194/** Convert, format and print a double according to the specifier.
     1195 *
     1196 * Depending on the specifier it prints the double using the styles
     1197 * %g, %f or %e by means of print_double_generic(), print_double_fixed(),
     1198 * print_double_scientific().
     1199 *
     1200 * @param g     Double to print.
     1201 * @param spec  Specifier of the style to print in; one of: 'g','G','f','F',
     1202 *              'e','E'.
     1203 * @param precision Number of fractional digits to display. If negative
     1204 *              the shortest accurate number will be printed for style %g;
     1205 *              negative precision defaults to 6 for styles %f, %e.
     1206 * @param width Minimum number of characters to display. Pads
     1207 *              with '0' or ' ' depending on the set flags;
     1208 * @param flags Printf flags.
     1209 * @param ps    Printing functions.
     1210 *
     1211 * @return The number of characters printed; negative on failure.
     1212 */
     1213static int print_double(double g, char spec, int precision, int width,
     1214        uint32_t flags, printf_spec_t *ps)
     1215{
     1216        switch (spec) {
     1217        case 'F':
     1218                flags |= __PRINTF_FLAG_BIGCHARS;
     1219                /* Fall through.*/
     1220        case 'f':
     1221                precision = (precision < 0) ? 6 : precision;
     1222                return print_double_fixed(g, precision, width, flags, ps);
     1223
     1224        case 'E':
     1225                flags |= __PRINTF_FLAG_BIGCHARS;
     1226                /* Fall through.*/
     1227        case 'e':
     1228                precision = (precision < 0) ? 6 : precision;
     1229                return print_double_scientific(g, precision, width, flags, ps);
     1230
     1231        case 'G':
     1232                flags |= __PRINTF_FLAG_BIGCHARS;
     1233                /* Fall through.*/
     1234        case 'g':
     1235                return print_double_generic(g, precision, width, flags, ps);
     1236
     1237        default:
     1238                assert(false);
     1239                return -1;
     1240        }
    5271241}
    5281242
     
    6561370                                case '#':
    6571371                                        flags |= __PRINTF_FLAG_PREFIX;
     1372                                        flags |= __PRINTF_FLAG_DECIMALPT;
    6581373                                        break;
    6591374                                case '-':
     
    7011416                       
    7021417                        /* Precision and '*' operator */
    703                         int precision = 0;
     1418                        int precision = -1;
    7041419                        if (uc == '.') {
    7051420                                i = nxt;
    7061421                                uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    7071422                                if (isdigit(uc)) {
     1423                                        precision = 0;
    7081424                                        while (true) {
    7091425                                                precision *= 10;
     
    7231439                                        precision = (int) va_arg(ap, int);
    7241440                                        if (precision < 0) {
    725                                                 /* Ignore negative precision */
    726                                                 precision = 0;
     1441                                                /* Ignore negative precision - use default instead */
     1442                                                precision = -1;
    7271443                                        }
    7281444                                }
     
    7741490                         */
    7751491                        case 's':
     1492                                precision = max(0,  precision);
     1493                               
    7761494                                if (qualifier == PrintfQualifierLong)
    7771495                                        retval = print_wstr(va_arg(ap, wchar_t *), width, precision, flags, ps);
     
    7971515                                        goto out;
    7981516                                };
     1517                               
     1518                                counter += retval;
     1519                                j = nxt;
     1520                                goto next_char;
     1521                               
     1522                        /*
     1523                         * Floating point values
     1524                         */
     1525                        case 'G':
     1526                        case 'g':
     1527                        case 'F':
     1528                        case 'f':
     1529                        case 'E':
     1530                        case 'e':
     1531                                retval = print_double(va_arg(ap, double), uc, precision,
     1532                                        width, flags, ps);
     1533                               
     1534                                if (retval < 0) {
     1535                                        counter = -counter;
     1536                                        goto out;
     1537                                }
    7991538                               
    8001539                                counter += retval;
  • uspace/lib/c/generic/time.c

    rfc89e32 r33c2952  
    11/*
    22 * Copyright (c) 2006 Ondrej Palkovsky
     3 * Copyright (c) 2011 Petr Koupy
     4 * Copyright (c) 2011 Jiri Zarevucky
    35 * All rights reserved.
    46 *
     
    4345#include <ddi.h>
    4446#include <libc.h>
     47#include <stdint.h>
     48#include <stdio.h>
     49#include <ctype.h>
     50#include <assert.h>
    4551#include <unistd.h>
     52#include <loc.h>
     53#include <device/clock_dev.h>
     54#include <malloc.h>
     55
     56#define ASCTIME_BUF_LEN 26
    4657
    4758/** Pointer to kernel shared variables with time */
     
    5263} *ktime = NULL;
    5364
     65/* Helper functions ***********************************************************/
     66
     67#define HOURS_PER_DAY (24)
     68#define MINS_PER_HOUR (60)
     69#define SECS_PER_MIN (60)
     70#define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY)
     71#define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR)
     72#define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY)
     73
     74/**
     75 * Checks whether the year is a leap year.
     76 *
     77 * @param year Year since 1900 (e.g. for 1970, the value is 70).
     78 * @return true if year is a leap year, false otherwise
     79 */
     80static bool _is_leap_year(time_t year)
     81{
     82        year += 1900;
     83
     84        if (year % 400 == 0)
     85                return true;
     86        if (year % 100 == 0)
     87                return false;
     88        if (year % 4 == 0)
     89                return true;
     90        return false;
     91}
     92
     93/**
     94 * Returns how many days there are in the given month of the given year.
     95 * Note that year is only taken into account if month is February.
     96 *
     97 * @param year Year since 1900 (can be negative).
     98 * @param mon Month of the year. 0 for January, 11 for December.
     99 * @return Number of days in the specified month.
     100 */
     101static int _days_in_month(time_t year, time_t mon)
     102{
     103        assert(mon >= 0 && mon <= 11);
     104
     105        static int month_days[] =
     106                { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
     107
     108        if (mon == 1) {
     109                year += 1900;
     110                /* february */
     111                return _is_leap_year(year) ? 29 : 28;
     112        } else {
     113                return month_days[mon];
     114        }
     115}
     116
     117/**
     118 * For specified year, month and day of month, returns which day of that year
     119 * it is.
     120 *
     121 * For example, given date 2011-01-03, the corresponding expression is:
     122 *     _day_of_year(111, 0, 3) == 2
     123 *
     124 * @param year Year (year 1900 = 0, can be negative).
     125 * @param mon Month (January = 0).
     126 * @param mday Day of month (First day is 1).
     127 * @return Day of year (First day is 0).
     128 */
     129static int _day_of_year(time_t year, time_t mon, time_t mday)
     130{
     131        static int mdays[] =
     132            { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
     133        static int leap_mdays[] =
     134            { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
     135
     136        return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1;
     137}
     138
     139/**
     140 * Integer division that rounds to negative infinity.
     141 * Used by some functions in this file.
     142 *
     143 * @param op1 Dividend.
     144 * @param op2 Divisor.
     145 * @return Rounded quotient.
     146 */
     147static time_t _floor_div(time_t op1, time_t op2)
     148{
     149        if (op1 >= 0 || op1 % op2 == 0) {
     150                return op1 / op2;
     151        } else {
     152                return op1 / op2 - 1;
     153        }
     154}
     155
     156/**
     157 * Modulo that rounds to negative infinity.
     158 * Used by some functions in this file.
     159 *
     160 * @param op1 Dividend.
     161 * @param op2 Divisor.
     162 * @return Remainder.
     163 */
     164static time_t _floor_mod(time_t op1, time_t op2)
     165{
     166        int div = _floor_div(op1, op2);
     167
     168        /* (a / b) * b + a % b == a */
     169        /* thus, a % b == a - (a / b) * b */
     170
     171        int result = op1 - div * op2;
     172       
     173        /* Some paranoid checking to ensure I didn't make a mistake here. */
     174        assert(result >= 0);
     175        assert(result < op2);
     176        assert(div * op2 + result == op1);
     177       
     178        return result;
     179}
     180
     181/**
     182 * Number of days since the Epoch.
     183 * Epoch is 1970-01-01, which is also equal to day 0.
     184 *
     185 * @param year Year (year 1900 = 0, may be negative).
     186 * @param mon Month (January = 0).
     187 * @param mday Day of month (first day = 1).
     188 * @return Number of days since the Epoch.
     189 */
     190static time_t _days_since_epoch(time_t year, time_t mon, time_t mday)
     191{
     192        return (year - 70) * 365 + _floor_div(year - 69, 4) -
     193            _floor_div(year - 1, 100) + _floor_div(year + 299, 400) +
     194            _day_of_year(year, mon, mday);
     195}
     196
     197/**
     198 * Seconds since the Epoch. see also _days_since_epoch().
     199 *
     200 * @param tm Normalized broken-down time.
     201 * @return Number of seconds since the epoch, not counting leap seconds.
     202 */
     203static time_t _secs_since_epoch(const struct tm *tm)
     204{
     205        return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) *
     206            SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR +
     207            tm->tm_min * SECS_PER_MIN + tm->tm_sec;
     208}
     209
     210/**
     211 * Which day of week the specified date is.
     212 *
     213 * @param year Year (year 1900 = 0).
     214 * @param mon Month (January = 0).
     215 * @param mday Day of month (first = 1).
     216 * @return Day of week (Sunday = 0).
     217 */
     218static int _day_of_week(time_t year, time_t mon, time_t mday)
     219{
     220        /* 1970-01-01 is Thursday */
     221        return _floor_mod((_days_since_epoch(year, mon, mday) + 4), 7);
     222}
     223
     224/**
     225 * Normalizes the broken-down time and optionally adds specified amount of
     226 * seconds.
     227 *
     228 * @param tm Broken-down time to normalize.
     229 * @param sec_add Seconds to add.
     230 * @return 0 on success, -1 on overflow
     231 */
     232static int _normalize_time(struct tm *tm, time_t sec_add)
     233{
     234        // TODO: DST correction
     235
     236        /* Set initial values. */
     237        time_t sec = tm->tm_sec + sec_add;
     238        time_t min = tm->tm_min;
     239        time_t hour = tm->tm_hour;
     240        time_t day = tm->tm_mday - 1;
     241        time_t mon = tm->tm_mon;
     242        time_t year = tm->tm_year;
     243
     244        /* Adjust time. */
     245        min += _floor_div(sec, SECS_PER_MIN);
     246        sec = _floor_mod(sec, SECS_PER_MIN);
     247        hour += _floor_div(min, MINS_PER_HOUR);
     248        min = _floor_mod(min, MINS_PER_HOUR);
     249        day += _floor_div(hour, HOURS_PER_DAY);
     250        hour = _floor_mod(hour, HOURS_PER_DAY);
     251
     252        /* Adjust month. */
     253        year += _floor_div(mon, 12);
     254        mon = _floor_mod(mon, 12);
     255
     256        /* Now the difficult part - days of month. */
     257       
     258        /* First, deal with whole cycles of 400 years = 146097 days. */
     259        year += _floor_div(day, 146097) * 400;
     260        day = _floor_mod(day, 146097);
     261       
     262        /* Then, go in one year steps. */
     263        if (mon <= 1) {
     264                /* January and February. */
     265                while (day > 365) {
     266                        day -= _is_leap_year(year) ? 366 : 365;
     267                        year++;
     268                }
     269        } else {
     270                /* Rest of the year. */
     271                while (day > 365) {
     272                        day -= _is_leap_year(year + 1) ? 366 : 365;
     273                        year++;
     274                }
     275        }
     276       
     277        /* Finally, finish it off month per month. */
     278        while (day >= _days_in_month(year, mon)) {
     279                day -= _days_in_month(year, mon);
     280                mon++;
     281                if (mon >= 12) {
     282                        mon -= 12;
     283                        year++;
     284                }
     285        }
     286       
     287        /* Calculate the remaining two fields. */
     288        tm->tm_yday = _day_of_year(year, mon, day + 1);
     289        tm->tm_wday = _day_of_week(year, mon, day + 1);
     290       
     291        /* And put the values back to the struct. */
     292        tm->tm_sec = (int) sec;
     293        tm->tm_min = (int) min;
     294        tm->tm_hour = (int) hour;
     295        tm->tm_mday = (int) day + 1;
     296        tm->tm_mon = (int) mon;
     297       
     298        /* Casts to work around libc brain-damage. */
     299        if (year > ((int)INT_MAX) || year < ((int)INT_MIN)) {
     300                tm->tm_year = (year < 0) ? ((int)INT_MIN) : ((int)INT_MAX);
     301                return -1;
     302        }
     303       
     304        tm->tm_year = (int) year;
     305        return 0;
     306}
     307
     308/**
     309 * Which day the week-based year starts on, relative to the first calendar day.
     310 * E.g. if the year starts on December 31st, the return value is -1.
     311 *
     312 * @param Year since 1900.
     313 * @return Offset of week-based year relative to calendar year.
     314 */
     315static int _wbyear_offset(int year)
     316{
     317        int start_wday = _day_of_week(year, 0, 1);
     318        return _floor_mod(4 - start_wday, 7) - 3;
     319}
     320
     321/**
     322 * Returns week-based year of the specified time.
     323 *
     324 * @param tm Normalized broken-down time.
     325 * @return Week-based year.
     326 */
     327static int _wbyear(const struct tm *tm)
     328{
     329        int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
     330        if (day < 0) {
     331                /* Last week of previous year. */
     332                return tm->tm_year - 1;
     333        }
     334        if (day > 364 + _is_leap_year(tm->tm_year)) {
     335                /* First week of next year. */
     336                return tm->tm_year + 1;
     337        }
     338        /* All the other days are in the calendar year. */
     339        return tm->tm_year;
     340}
     341
     342/**
     343 * Week number of the year, assuming weeks start on sunday.
     344 * The first Sunday of January is the first day of week 1;
     345 * days in the new year before this are in week 0.
     346 *
     347 * @param tm Normalized broken-down time.
     348 * @return The week number (0 - 53).
     349 */
     350static int _sun_week_number(const struct tm *tm)
     351{
     352        int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7;
     353        return (tm->tm_yday - first_day + 7) / 7;
     354}
     355
     356/**
     357 * Week number of the year, assuming weeks start on monday.
     358 * If the week containing January 1st has four or more days in the new year,
     359 * then it is considered week 1. Otherwise, it is the last week of the previous
     360 * year, and the next week is week 1. Both January 4th and the first Thursday
     361 * of January are always in week 1.
     362 *
     363 * @param tm Normalized broken-down time.
     364 * @return The week number (1 - 53).
     365 */
     366static int _iso_week_number(const struct tm *tm)
     367{
     368        int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
     369        if (day < 0) {
     370                /* Last week of previous year. */
     371                return 53;
     372        }
     373        if (day > 364 + _is_leap_year(tm->tm_year)) {
     374                /* First week of next year. */
     375                return 1;
     376        }
     377        /* All the other days give correct answer. */
     378        return (day / 7 + 1);
     379}
     380
     381/**
     382 * Week number of the year, assuming weeks start on monday.
     383 * The first Monday of January is the first day of week 1;
     384 * days in the new year before this are in week 0.
     385 *
     386 * @param tm Normalized broken-down time.
     387 * @return The week number (0 - 53).
     388 */
     389static int _mon_week_number(const struct tm *tm)
     390{
     391        int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7;
     392        return (tm->tm_yday - first_day + 7) / 7;
     393}
     394
     395/******************************************************************************/
     396
     397
    54398/** Add microseconds to given timeval.
    55399 *
     
    139483 */
    140484int gettimeofday(struct timeval *tv, struct timezone *tz)
     485{
     486        int rc;
     487        struct tm t;
     488        category_id_t cat_id;
     489        size_t svc_cnt;
     490        service_id_t *svc_ids = NULL;
     491        service_id_t svc_id;
     492        char *svc_name = NULL;
     493
     494        static async_sess_t *clock_conn = NULL;
     495
     496        if (tz) {
     497                tz->tz_minuteswest = 0;
     498                tz->tz_dsttime = DST_NONE;
     499        }
     500
     501        if (clock_conn == NULL) {
     502                rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
     503                if (rc != EOK)
     504                        goto ret_uptime;
     505
     506                rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt);
     507                if (rc != EOK)
     508                        goto ret_uptime;
     509
     510                if (svc_cnt == 0)
     511                        goto ret_uptime;
     512
     513                rc = loc_service_get_name(svc_ids[0], &svc_name);
     514                if (rc != EOK)
     515                        goto ret_uptime;
     516
     517                rc = loc_service_get_id(svc_name, &svc_id, 0);
     518                if (rc != EOK)
     519                        goto ret_uptime;
     520
     521                clock_conn = loc_service_connect(EXCHANGE_SERIALIZE,
     522                    svc_id, IPC_FLAG_BLOCKING);
     523                if (!clock_conn)
     524                        goto ret_uptime;
     525        }
     526
     527        rc = clock_dev_time_get(clock_conn, &t);
     528        if (rc != EOK)
     529                goto ret_uptime;
     530
     531        tv->tv_usec = 0;
     532        tv->tv_sec = mktime(&t);
     533
     534        free(svc_name);
     535        free(svc_ids);
     536
     537        return EOK;
     538
     539ret_uptime:
     540
     541        free(svc_name);
     542        free(svc_ids);
     543
     544        return getuptime(tv);
     545}
     546
     547int getuptime(struct timeval *tv)
    141548{
    142549        if (ktime == NULL) {
     
    160567        }
    161568       
    162         if (tz) {
    163                 tz->tz_minuteswest = 0;
    164                 tz->tz_dsttime = DST_NONE;
    165         }
    166        
    167569        sysarg_t s2 = ktime->seconds2;
    168570       
     
    178580        } else
    179581                tv->tv_sec = s1;
    180        
     582
    181583        return 0;
    182584}
     
    229631}
    230632
     633/**
     634 * This function first normalizes the provided broken-down time
     635 * (moves all values to their proper bounds) and then tries to
     636 * calculate the appropriate time_t representation.
     637 *
     638 * @param tm Broken-down time.
     639 * @return time_t representation of the time, undefined value on overflow.
     640 */
     641time_t mktime(struct tm *tm)
     642{
     643        // TODO: take DST flag into account
     644        // TODO: detect overflow
     645
     646        _normalize_time(tm, 0);
     647        return _secs_since_epoch(tm);
     648}
     649
     650/**
     651 * Convert time and date to a string, based on a specified format and
     652 * current locale.
     653 *
     654 * @param s Buffer to write string to.
     655 * @param maxsize Size of the buffer.
     656 * @param format Format of the output.
     657 * @param tm Broken-down time to format.
     658 * @return Number of bytes written.
     659 */
     660size_t strftime(char *restrict s, size_t maxsize,
     661    const char *restrict format, const struct tm *restrict tm)
     662{
     663        assert(s != NULL);
     664        assert(format != NULL);
     665        assert(tm != NULL);
     666
     667        // TODO: use locale
     668        static const char *wday_abbr[] = {
     669                "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
     670        };
     671        static const char *wday[] = {
     672                "Sunday", "Monday", "Tuesday", "Wednesday",
     673                "Thursday", "Friday", "Saturday"
     674        };
     675        static const char *mon_abbr[] = {
     676                "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     677                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
     678        };
     679        static const char *mon[] = {
     680                "January", "February", "March", "April", "May", "June", "July",
     681                "August", "September", "October", "November", "December"
     682        };
     683       
     684        if (maxsize < 1) {
     685                return 0;
     686        }
     687       
     688        char *ptr = s;
     689        size_t consumed;
     690        size_t remaining = maxsize;
     691       
     692        #define append(...) { \
     693                /* FIXME: this requires POSIX-correct snprintf */ \
     694                /*        otherwise it won't work with non-ascii chars */ \
     695                consumed = snprintf(ptr, remaining, __VA_ARGS__); \
     696                if (consumed >= remaining) { \
     697                        return 0; \
     698                } \
     699                ptr += consumed; \
     700                remaining -= consumed; \
     701        }
     702       
     703        #define recurse(fmt) { \
     704                consumed = strftime(ptr, remaining, fmt, tm); \
     705                if (consumed == 0) { \
     706                        return 0; \
     707                } \
     708                ptr += consumed; \
     709                remaining -= consumed; \
     710        }
     711       
     712        #define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \
     713            (((hour) == 0) ? 12 : (hour)))
     714       
     715        while (*format != '\0') {
     716                if (*format != '%') {
     717                        append("%c", *format);
     718                        format++;
     719                        continue;
     720                }
     721               
     722                format++;
     723                if (*format == '0' || *format == '+') {
     724                        // TODO: padding
     725                        format++;
     726                }
     727                while (isdigit(*format)) {
     728                        // TODO: padding
     729                        format++;
     730                }
     731                if (*format == 'O' || *format == 'E') {
     732                        // TODO: locale's alternative format
     733                        format++;
     734                }
     735               
     736                switch (*format) {
     737                case 'a':
     738                        append("%s", wday_abbr[tm->tm_wday]); break;
     739                case 'A':
     740                        append("%s", wday[tm->tm_wday]); break;
     741                case 'b':
     742                        append("%s", mon_abbr[tm->tm_mon]); break;
     743                case 'B':
     744                        append("%s", mon[tm->tm_mon]); break;
     745                case 'c':
     746                        // TODO: locale-specific datetime format
     747                        recurse("%Y-%m-%d %H:%M:%S"); break;
     748                case 'C':
     749                        append("%02d", (1900 + tm->tm_year) / 100); break;
     750                case 'd':
     751                        append("%02d", tm->tm_mday); break;
     752                case 'D':
     753                        recurse("%m/%d/%y"); break;
     754                case 'e':
     755                        append("%2d", tm->tm_mday); break;
     756                case 'F':
     757                        recurse("%+4Y-%m-%d"); break;
     758                case 'g':
     759                        append("%02d", _wbyear(tm) % 100); break;
     760                case 'G':
     761                        append("%d", _wbyear(tm)); break;
     762                case 'h':
     763                        recurse("%b"); break;
     764                case 'H':
     765                        append("%02d", tm->tm_hour); break;
     766                case 'I':
     767                        append("%02d", TO_12H(tm->tm_hour)); break;
     768                case 'j':
     769                        append("%03d", tm->tm_yday); break;
     770                case 'k':
     771                        append("%2d", tm->tm_hour); break;
     772                case 'l':
     773                        append("%2d", TO_12H(tm->tm_hour)); break;
     774                case 'm':
     775                        append("%02d", tm->tm_mon); break;
     776                case 'M':
     777                        append("%02d", tm->tm_min); break;
     778                case 'n':
     779                        append("\n"); break;
     780                case 'p':
     781                        append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break;
     782                case 'P':
     783                        append("%s", tm->tm_hour < 12 ? "am" : "PM"); break;
     784                case 'r':
     785                        recurse("%I:%M:%S %p"); break;
     786                case 'R':
     787                        recurse("%H:%M"); break;
     788                case 's':
     789                        append("%ld", _secs_since_epoch(tm)); break;
     790                case 'S':
     791                        append("%02d", tm->tm_sec); break;
     792                case 't':
     793                        append("\t"); break;
     794                case 'T':
     795                        recurse("%H:%M:%S"); break;
     796                case 'u':
     797                        append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
     798                        break;
     799                case 'U':
     800                        append("%02d", _sun_week_number(tm)); break;
     801                case 'V':
     802                        append("%02d", _iso_week_number(tm)); break;
     803                case 'w':
     804                        append("%d", tm->tm_wday); break;
     805                case 'W':
     806                        append("%02d", _mon_week_number(tm)); break;
     807                case 'x':
     808                        // TODO: locale-specific date format
     809                        recurse("%Y-%m-%d"); break;
     810                case 'X':
     811                        // TODO: locale-specific time format
     812                        recurse("%H:%M:%S"); break;
     813                case 'y':
     814                        append("%02d", tm->tm_year % 100); break;
     815                case 'Y':
     816                        append("%d", 1900 + tm->tm_year); break;
     817                case 'z':
     818                        // TODO: timezone
     819                        break;
     820                case 'Z':
     821                        // TODO: timezone
     822                        break;
     823                case '%':
     824                        append("%%");
     825                        break;
     826                default:
     827                        /* Invalid specifier, print verbatim. */
     828                        while (*format != '%') {
     829                                format--;
     830                        }
     831                        append("%%");
     832                        break;
     833                }
     834                format++;
     835        }
     836       
     837        #undef append
     838        #undef recurse
     839       
     840        return maxsize - remaining;
     841}
     842
     843
     844/** Converts a time value to a broken-down UTC time
     845 *
     846 * @param time    Time to convert
     847 * @param result  Structure to store the result to
     848 *
     849 * @return        EOK or a negative error code
     850 */
     851int time_utc2tm(const time_t time, struct tm *restrict result)
     852{
     853        assert(result != NULL);
     854
     855        /* Set result to epoch. */
     856        result->tm_sec = 0;
     857        result->tm_min = 0;
     858        result->tm_hour = 0;
     859        result->tm_mday = 1;
     860        result->tm_mon = 0;
     861        result->tm_year = 70; /* 1970 */
     862
     863        if (_normalize_time(result, time) == -1)
     864                return EOVERFLOW;
     865
     866        return EOK;
     867}
     868
     869/** Converts a time value to a null terminated string of the form
     870 *  "Wed Jun 30 21:49:08 1993\n" expressed in UTC.
     871 *
     872 * @param time   Time to convert.
     873 * @param buf    Buffer to store the string to, must be at least
     874 *               ASCTIME_BUF_LEN bytes long.
     875 *
     876 * @return       EOK or a negative error code.
     877 */
     878int time_utc2str(const time_t time, char *restrict buf)
     879{
     880        struct tm t;
     881        int r;
     882
     883        if ((r = time_utc2tm(time, &t)) != EOK)
     884                return r;
     885
     886        time_tm2str(&t, buf);
     887        return EOK;
     888}
     889
     890
     891/**
     892 * Converts broken-down time to a string in format
     893 * "Sun Jan 1 00:00:00 1970\n". (Obsolete)
     894 *
     895 * @param timeptr Broken-down time structure.
     896 * @param buf     Buffer to store string to, must be at least ASCTIME_BUF_LEN
     897 *                bytes long.
     898 */
     899void time_tm2str(const struct tm *restrict timeptr, char *restrict buf)
     900{
     901        assert(timeptr != NULL);
     902        assert(buf != NULL);
     903
     904        static const char *wday[] = {
     905                "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
     906        };
     907        static const char *mon[] = {
     908                "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     909                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
     910        };
     911
     912        snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n",
     913            wday[timeptr->tm_wday],
     914            mon[timeptr->tm_mon],
     915            timeptr->tm_mday, timeptr->tm_hour,
     916            timeptr->tm_min, timeptr->tm_sec,
     917            1900 + timeptr->tm_year);
     918}
     919
     920/**
     921 * Converts a time value to a broken-down local time, expressed relative
     922 * to the user's specified timezone.
     923 *
     924 * @param timer     Time to convert.
     925 * @param result    Structure to store the result to.
     926 *
     927 * @return          EOK on success or a negative error code.
     928 */
     929int time_local2tm(const time_t time, struct tm *restrict result)
     930{
     931        // TODO: deal with timezone
     932        // currently assumes system and all times are in GMT
     933
     934        /* Set result to epoch. */
     935        result->tm_sec = 0;
     936        result->tm_min = 0;
     937        result->tm_hour = 0;
     938        result->tm_mday = 1;
     939        result->tm_mon = 0;
     940        result->tm_year = 70; /* 1970 */
     941
     942        if (_normalize_time(result, time) == -1)
     943                return EOVERFLOW;
     944
     945        return EOK;
     946}
     947
     948/**
     949 * Converts the calendar time to a null terminated string
     950 * of the form "Wed Jun 30 21:49:08 1993\n" expressed relative to the
     951 * user's specified timezone.
     952 *
     953 * @param timer  Time to convert.
     954 * @param buf    Buffer to store the string to. Must be at least
     955 *               ASCTIME_BUF_LEN bytes long.
     956 *
     957 * @return       EOK on success or a negative error code.
     958 */
     959int time_local2str(const time_t time, char *buf)
     960{
     961        struct tm loctime;
     962        int r;
     963
     964        if ((r = time_local2tm(time, &loctime)) != EOK)
     965                return r;
     966
     967        time_tm2str(&loctime, buf);
     968
     969        return EOK;
     970}
     971
     972/**
     973 * Calculate the difference between two times, in seconds.
     974 *
     975 * @param time1 First time.
     976 * @param time0 Second time.
     977 * @return Time in seconds.
     978 */
     979double difftime(time_t time1, time_t time0)
     980{
     981        return (double) (time1 - time0);
     982}
     983
    231984/** @}
    232985 */
  • uspace/lib/c/generic/tls.c

    rfc89e32 r33c2952  
    4242#include <str.h>
    4343#include <align.h>
     44#include <unistd.h>
    4445
    4546/** Create TLS (Thread Local Storage) data structures.
     
    5758       
    5859        tcb = __alloc_tls(&data, tls_size);
     60        if (!tcb)
     61                return NULL;
    5962       
    6063        /*
     
    8992
    9093        result = malloc(sizeof(tcb_t) + size);
     94        if (!result)
     95                return NULL;
    9196        *data = ((void *)result) + sizeof(tcb_t);
     97
    9298        return result;
    9399}
     
    118124        size = ALIGN_UP(size, &_tls_alignment);
    119125        *data = memalign((uintptr_t) &_tls_alignment, sizeof(tcb_t) + size);
    120 
     126        if (!*data)
     127                return NULL;
    121128        tcb = (tcb_t *) (*data + size);
    122129        tcb->self = tcb;
  • uspace/lib/c/include/io/console.h

    rfc89e32 r33c2952  
    3737
    3838#include <sys/time.h>
     39#include <io/concaps.h>
    3940#include <io/kbd_event.h>
    4041#include <io/keycode.h>
     
    4243#include <bool.h>
    4344#include <stdio.h>
    44 
    45 typedef enum {
    46         CONSOLE_CAP_NONE = 0,
    47         CONSOLE_CAP_STYLE = 1,
    48         CONSOLE_CAP_INDEXED = 2,
    49         CONSOLE_CAP_RGB = 4
    50 } console_caps_t;
    5145
    5246/** Console control structure. */
  • uspace/lib/c/include/io/klog.h

    rfc89e32 r33c2952  
    3838#include <sys/types.h>
    3939#include <stdarg.h>
     40#include <io/verify.h>
    4041
    4142extern size_t klog_write(const void *, size_t);
    4243extern void klog_update(void);
    43 extern int klog_printf(const char *, ...);
     44extern int klog_printf(const char *, ...)
     45    PRINTF_ATTRIBUTE(1, 2);
    4446extern int klog_vprintf(const char *, va_list);
    4547
  • uspace/lib/c/include/io/log.h

    rfc89e32 r33c2952  
    3636
    3737#include <stdarg.h>
     38#include <inttypes.h>
     39#include <io/verify.h>
    3840
     41/** Log message level. */
    3942typedef enum {
     43        /** Fatal error, program is not able to recover at all. */
    4044        LVL_FATAL,
     45        /** Serious error but the program can recover from it. */
    4146        LVL_ERROR,
     47        /** Easily recoverable problem. */
    4248        LVL_WARN,
     49        /** Information message that ought to be printed by default. */
    4350        LVL_NOTE,
     51        /** Debugging purpose message. */
    4452        LVL_DEBUG,
     53        /** More detailed debugging message. */
    4554        LVL_DEBUG2,
    46 
     55       
    4756        /** For checking range of values */
    4857        LVL_LIMIT
    4958} log_level_t;
    5059
    51 extern int log_init(const char *, log_level_t);
    52 extern void log_msg(log_level_t, const char *, ...);
    53 extern void log_msgv(log_level_t, const char *, va_list);
     60/** Log itself (logging target). */
     61typedef sysarg_t log_t;
     62/** Formatting directive for printing log_t. */
     63#define PRIlogctx PRIxn
     64
     65/** Default log (target). */
     66#define LOG_DEFAULT ((log_t) -1)
     67
     68/** Use when creating new top-level log. */
     69#define LOG_NO_PARENT ((log_t) 0)
     70
     71extern const char *log_level_str(log_level_t);
     72extern int log_level_from_str(const char *, log_level_t *);
     73
     74extern int log_init(const char *);
     75extern log_t log_create(const char *, log_t);
     76
     77extern void log_msg(log_t, log_level_t, const char *, ...)
     78    PRINTF_ATTRIBUTE(3, 4);
     79extern void log_msgv(log_t, log_level_t, const char *, va_list);
    5480
    5581#endif
  • uspace/lib/c/include/ipc/console.h

    rfc89e32 r33c2952  
    4343        CONSOLE_GET_EVENT,
    4444        CONSOLE_GET_POS,
    45         CONSOLE_GOTO,
     45        CONSOLE_SET_POS,
    4646        CONSOLE_CLEAR,
    4747        CONSOLE_SET_STYLE,
    4848        CONSOLE_SET_COLOR,
    4949        CONSOLE_SET_RGB_COLOR,
    50         CONSOLE_CURSOR_VISIBILITY
     50        CONSOLE_SET_CURSOR_VISIBILITY
    5151} console_request_t;
    5252
  • uspace/lib/c/include/ipc/dev_iface.h

    rfc89e32 r33c2952  
    5454        /** Interface provided by USB HID devices. */
    5555        USBHID_DEV_IFACE,
     56        /** Interface provided by Real Time Clock devices */
     57        CLOCK_DEV_IFACE,
     58        /** Interface provided by battery powered devices */
     59        BATTERY_DEV_IFACE,
    5660        /** Interface provided by AHCI devices. */
    5761        AHCI_DEV_IFACE,
  • uspace/lib/c/include/ipc/services.h

    rfc89e32 r33c2952  
    4545        SERVICE_VFS        = FOURCC('v', 'f', 's', ' '),
    4646        SERVICE_LOC        = FOURCC('l', 'o', 'c', ' '),
     47        SERVICE_LOGGER     = FOURCC('l', 'o', 'g', 'g'),
    4748        SERVICE_DEVMAN     = FOURCC('d', 'e', 'v', 'n'),
    4849        SERVICE_IRC        = FOURCC('i', 'r', 'c', ' '),
  • uspace/lib/c/include/macros.h

    rfc89e32 r33c2952  
    3838#define min(a, b)  ((a) < (b) ? (a) : (b))
    3939#define max(a, b)  ((a) > (b) ? (a) : (b))
     40#define abs(a)     ((a) >= 0 ? (a) : (-a))
     41
    4042
    4143#define KiB2SIZE(kb)  ((kb) << 10)
  • uspace/lib/c/include/stdio.h

    rfc89e32 r33c2952  
    3939#include <stdarg.h>
    4040#include <str.h>
    41 
    42 #ifndef NVERIFY_PRINTF
    43 
    44 #define PRINTF_ATTRIBUTE(start, end) \
    45         __attribute__((format(gnu_printf, start, end)))
    46 
    47 #else /* NVERIFY_PRINTF */
    48 
    49 #define PRINTF_ATTRIBUTE(start, end)
    50 
    51 #endif /* NVERIFY_PRINTF */
     41#include <io/verify.h>
    5242
    5343#define EOF  (-1)
  • uspace/lib/c/include/sys/time.h

    rfc89e32 r33c2952  
    11/*
    22 * Copyright (c) 2006 Ondrej Palkovsky
     3 * Copyright (c) 2011 Petr Koupy
     4 * Copyright (c) 2011 Jiri Zarevucky
    35 * All rights reserved.
    46 *
     
    3941
    4042#define DST_NONE 0
     43#define ASCTIME_BUF_LEN 26
    4144
    4245typedef long time_t;
     
    4548typedef uint32_t useconds_t;
    4649typedef uint32_t mseconds_t;
     50
     51struct tm {
     52        int tm_sec;         /* Seconds [0,60]. */
     53        int tm_min;         /* Minutes [0,59]. */
     54        int tm_hour;        /* Hour [0,23]. */
     55        int tm_mday;        /* Day of month [1,31]. */
     56        int tm_mon;         /* Month of year [0,11]. */
     57        int tm_year;        /* Years since 1900. */
     58        int tm_wday;        /* Day of week [0,6] (Sunday = 0). */
     59        int tm_yday;        /* Day of year [0,365]. */
     60        int tm_isdst;       /* Daylight Savings flag. */
     61};
    4762
    4863struct timeval {
     
    6176extern int tv_gteq(struct timeval *tv1, struct timeval *tv2);
    6277extern int gettimeofday(struct timeval *tv, struct timezone *tz);
     78extern int getuptime(struct timeval *tv);
    6379
    6480extern void udelay(useconds_t);
     81
     82extern time_t mktime(struct tm *tm);
     83extern int time_utc2tm(const time_t time, struct tm *result);
     84extern int time_utc2str(const time_t time, char *buf);
     85extern void time_tm2str(const struct tm *timeptr, char *buf);
     86extern int time_local2tm(const time_t time, struct tm *result);
     87extern int time_local2str(const time_t time, char *buf);
     88extern double difftime(time_t time1, time_t time0);
     89extern size_t strftime(char *restrict s, size_t maxsize,
     90    const char *restrict format, const struct tm *restrict tm);
    6591
    6692#endif
Note: See TracChangeset for help on using the changeset viewer.