15c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* 25c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * Copyright (C) 2010 The Android Open Source Project 35c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * All rights reserved. 45c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * 55c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * Redistribution and use in source and binary forms, with or without 65c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * modification, are permitted provided that the following conditions 75c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * are met: 85c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * * Redistributions of source code must retain the above copyright 95c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * notice, this list of conditions and the following disclaimer. 105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * * Redistributions in binary form must reproduce the above copyright 115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * notice, this list of conditions and the following disclaimer in 125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * the documentation and/or other materials provided with the 135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * distribution. 145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * 155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * SUCH DAMAGE. 275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <stdarg.h> 305c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <string.h> 315c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <errno.h> 325c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <unistd.h> 335c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <stdint.h> 345c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <stddef.h> 355c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include "linker_format.h" 365c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include "linker_debug.h" 375c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* define UNIT_TESTS to build this file as a single executable that runs 395c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * the formatter's unit tests 405c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 415c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#define xxUNIT_TESTS 425c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 435c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/*** Generic output sink 445c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ***/ 455c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 465c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnertypedef struct { 475c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner void *opaque; 485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner void (*send)(void *opaque, const char *data, int len); 495c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} Out; 505c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 515c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerout_send(Out *o, const void *data, size_t len) 535c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner o->send(o->opaque, data, (int)len); 555c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerout_send_repeat(Out *o, char ch, int count) 595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char pad[8]; 615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner const int padSize = (int)sizeof(pad); 625c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner memset(pad, ch, sizeof(pad)); 645c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner while (count > 0) { 655c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int avail = count; 665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (avail > padSize) { 675c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner avail = padSize; 685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 695c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner o->send(o->opaque, pad, avail); 705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner count -= avail; 715c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 725c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 735c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* forward declaration */ 755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 765c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerout_vformat(Out *o, const char *format, va_list args); 775c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/*** Bounded buffer output 795c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ***/ 805c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnertypedef struct { 825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner Out out[1]; 835c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char *buffer; 845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char *pos; 855c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char *end; 865c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int total; 875c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} BufOut; 885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 895c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerbuf_out_send(void *opaque, const char *data, int len) 915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner BufOut *bo = opaque; 935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (len < 0) 955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner len = strlen(data); 965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bo->total += len; 985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner while (len > 0) { 1005c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int avail = bo->end - bo->pos; 1015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (avail == 0) 1025c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 1035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (avail > len) 1045c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner avail = len; 1055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner memcpy(bo->pos, data, avail); 1065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bo->pos += avail; 1075c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bo->pos[0] = '\0'; 1085c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner len -= avail; 1095c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 1105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 1115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic Out* 1135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerbuf_out_init(BufOut *bo, char *buffer, size_t size) 1145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 1155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (size == 0) 1165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return NULL; 1175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bo->out->opaque = bo; 1195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bo->out->send = buf_out_send; 1205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bo->buffer = buffer; 1215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bo->end = buffer + size - 1; 1225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bo->pos = bo->buffer; 1235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bo->pos[0] = '\0'; 1245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bo->total = 0; 1255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return bo->out; 1275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 1285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic int 1305c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerbuf_out_length(BufOut *bo) 1315c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 1325c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return bo->total; 1335c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 1345c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1355c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic int 1365c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnervformat_buffer(char *buff, size_t buffsize, const char *format, va_list args) 1375c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 1385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner BufOut bo; 1395c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner Out *out; 1405c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1415c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out = buf_out_init(&bo, buff, buffsize); 1425c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (out == NULL) 1435c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return 0; 1445c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1455c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_vformat(out, format, args); 1465c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1475c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return buf_out_length(&bo); 1485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 1495c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1505c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerint 1515c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerformat_buffer(char *buff, size_t buffsize, const char *format, ...) 1525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 1535c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_list args; 1545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int ret; 1555c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_start(args, format); 1575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ret = vformat_buffer(buff, buffsize, format, args); 1585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_end(args); 1595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return ret; 1615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 1625c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* The __stack_chk_fail() function calls __libc_android_log_print() 1645c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * which calls vsnprintf(). 1655c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * 1665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * We define our version of the function here to avoid dragging 1675c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * about 25 KB of C library routines related to formatting. 1685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 1695c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerint 1705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnervsnprintf(char *buff, size_t bufsize, const char *format, va_list args) 1715c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 1725c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return format_buffer(buff, bufsize, format, args); 1735c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 1745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#if LINKER_DEBUG 1765c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1775c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#if !LINKER_DEBUG_TO_LOG 1785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1795c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/*** File descriptor output 1805c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ***/ 1815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnertypedef struct { 1835c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner Out out[1]; 1845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int fd; 1855c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int total; 1865c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} FdOut; 1875c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 1895c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerfd_out_send(void *opaque, const char *data, int len) 1905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 1915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner FdOut *fdo = opaque; 1925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (len < 0) 1945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner len = strlen(data); 1955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner while (len > 0) { 1975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int ret = write(fdo->fd, data, len); 1985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (ret < 0) { 1995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (errno == EINTR) 2005c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner continue; 2015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 2025c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 2035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner data += ret; 2045c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner len -= ret; 2055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner fdo->total += ret; 2065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 2075c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 2085c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2095c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic Out* 2105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerfd_out_init(FdOut *fdo, int fd) 2115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 2125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner fdo->out->opaque = fdo; 2135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner fdo->out->send = fd_out_send; 2145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner fdo->fd = fd; 2155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner fdo->total = 0; 2165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return fdo->out; 2185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 2195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic int 2215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerfd_out_length(FdOut *fdo) 2225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 2235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return fdo->total; 2245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 2255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerint 2285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerformat_fd(int fd, const char *format, ...) 2295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 2305c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner FdOut fdo; 2315c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner Out* out; 2325c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_list args; 2335c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2345c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out = fd_out_init(&fdo, fd); 2355c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (out == NULL) 2365c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return 0; 2375c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_start(args, format); 2395c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_vformat(out, format, args); 2405c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_end(args); 2415c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2425c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return fd_out_length(&fdo); 2435c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 2445c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2455c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#else /* LINKER_DEBUG_TO_LOG */ 2465c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2475c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/*** Log output 2485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ***/ 2495c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2505c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* We need our own version of __libc_android_log_vprint, otherwise 2515c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * the log output is completely broken. Probably due to the fact 2525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * that the C library is not initialized yet. 2535c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * 2545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * You can test that by setting CUSTOM_LOG_VPRINT to 0 2555c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 2565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#define CUSTOM_LOG_VPRINT 1 2575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#if CUSTOM_LOG_VPRINT 2595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <unistd.h> 2615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <fcntl.h> 2625c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <sys/uio.h> 2635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2645c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic int log_vprint(int prio, const char *tag, const char *fmt, va_list args) 2655c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 2665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char buf[1024]; 2675c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int result; 2685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner static int log_fd = -1; 2695c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner result = vformat_buffer(buf, sizeof buf, fmt, args); 2715c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2725c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (log_fd < 0) { 2735c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner log_fd = open("/dev/log/main", O_WRONLY); 2745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (log_fd < 0) 2755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return result; 2765c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 2775c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner { 2795c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ssize_t ret; 2805c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner struct iovec vec[3]; 2815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner vec[0].iov_base = (unsigned char *) &prio; 2835c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner vec[0].iov_len = 1; 2845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner vec[1].iov_base = (void *) tag; 2855c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner vec[1].iov_len = strlen(tag) + 1; 2865c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner vec[2].iov_base = (void *) buf; 2875c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner vec[2].iov_len = strlen(buf) + 1; 2885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2895c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner do { 2905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ret = writev(log_fd, vec, 3); 2915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } while ((ret < 0) && (errno == EINTR)); 2925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 2935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return result; 2945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 2955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#define __libc_android_log_vprint log_vprint 2975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#else /* !CUSTOM_LOG_VPRINT */ 2995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3005c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerextern int __libc_android_log_vprint(int prio, const char* tag, const char* format, va_list ap); 3015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3025c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#endif /* !CUSTOM_LOG_VPRINT */ 3035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3045c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerint 3055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerformat_log(int prio, const char *tag, const char *format, ...) 3065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 3075c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int ret; 3085c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_list args; 3095c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_start(args, format); 3105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ret = __libc_android_log_vprint(prio, tag, format, args); 3115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_end(args); 3125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return ret; 3135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 3145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#endif /* LINKER_DEBUG_TO_LOG */ 3165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#endif /* LINKER_DEBUG */ 3185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/*** formatted output implementation 3205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ***/ 3215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* Parse a decimal string from 'format + *ppos', 3235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * return the value, and writes the new position past 3245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * the decimal string in '*ppos' on exit. 3255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * 3265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * NOTE: Does *not* handle a sign prefix. 3275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 3285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic unsigned 3295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerparse_decimal(const char *format, int *ppos) 3305c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 3315c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner const char* p = format + *ppos; 3325c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner unsigned result = 0; 3335c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3345c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner for (;;) { 3355c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int ch = *p; 3365c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner unsigned d = (unsigned)(ch - '0'); 3375c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (d >= 10U) 3395c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 3405c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3415c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner result = result*10 + d; 3425c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner p++; 3435c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3445c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner *ppos = p - format; 3455c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return result; 3465c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 3475c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* write an octal/decimal/number into a bounded buffer. 3495c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * assumes that bufsize > 0, and 'digits' is a string of 3505c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * digits of at least 'base' values. 3515c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 3525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 3535c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerformat_number(char *buffer, size_t bufsize, uint64_t value, int base, const char *digits) 3545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 3555c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char *pos = buffer; 3565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char *end = buffer + bufsize - 1; 3575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* generate digit string in reverse order */ 3595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner while (value) { 3605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner unsigned d = value % base; 3615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner value /= base; 3625c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (pos < end) { 3635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner *pos++ = digits[d]; 3645c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3655c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3675c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* special case for 0 */ 3685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (pos == buffer) { 3695c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (pos < end) { 3705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner *pos++ = '0'; 3715c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3725c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3735c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner pos[0] = '\0'; 3745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* now reverse digit string in-place */ 3765c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner end = pos - 1; 3775c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner pos = buffer; 3785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner while (pos < end) { 3795c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int ch = pos[0]; 3805c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner pos[0] = end[0]; 3815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner end[0] = (char) ch; 3825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner pos++; 3835c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner end--; 3845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3855c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 3865c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3875c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */ 3885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 3895c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerformat_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned) 3905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 3915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (isSigned && (int64_t)value < 0) { 3925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[0] = '-'; 3935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer += 1; 3945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffsize -= 1; 3955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner value = (uint64_t)(-(int64_t)value); 3965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner format_number(buffer, buffsize, value, base, "0123456789"); 3995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 4005c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* Write an octal into a buffer, assumes buffsize > 2 */ 4025c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 4035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerformat_octal(char *buffer, size_t buffsize, uint64_t value, int isSigned) 4045c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 4055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner format_integer(buffer, buffsize, value, 8, isSigned); 4065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 4075c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4085c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* Write a decimal into a buffer, assumes buffsize > 2 */ 4095c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 4105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerformat_decimal(char *buffer, size_t buffsize, uint64_t value, int isSigned) 4115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 4125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner format_integer(buffer, buffsize, value, 10, isSigned); 4135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 4145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* Write an hexadecimal into a buffer, isCap is true for capital alphas. 4165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * Assumes bufsize > 2 */ 4175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 4185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerformat_hex(char *buffer, size_t buffsize, uint64_t value, int isCap) 4195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 4205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner const char *digits = isCap ? "0123456789ABCDEF" : "0123456789abcdef"; 4215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner format_number(buffer, buffsize, value, 16, digits); 4235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 4245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* Perform formatted output to an output target 'o' */ 4275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 4285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerout_vformat(Out *o, const char *format, va_list args) 4295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 430ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int nn = 0; 4315c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4325c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner for (;;) { 433ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int mm; 434ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int padZero = 0; 435ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int padLeft = 0; 436ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden char sign = '\0'; 437ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int width = -1; 438ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int prec = -1; 439ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden size_t bytelen = sizeof(int); 440ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden const char* str; 441ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int slen; 442ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden char buffer[32]; /* temporary buffer used to format numbers */ 443ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden 4445c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char c; 4455c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4465c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* first, find all characters that are not 0 or '%' */ 4475c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* then send them to the output directly */ 4485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner mm = nn; 4495c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner do { 4505c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[mm]; 4515c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == '\0' || c == '%') 4525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 4535c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner mm++; 4545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } while (1); 4555c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (mm > nn) { 4575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send(o, format+nn, mm-nn); 4585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn = mm; 4595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* is this it ? then exit */ 4625c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == '\0') 4635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 4645c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4655c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* nope, we are at a '%' modifier */ 4665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn++; // skip it 4675c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* parse flags */ 4695c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner for (;;) { 4705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 4715c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == '\0') { /* single trailing '%' ? */ 4725c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = '%'; 4735c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send(o, &c, 1); 4745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return; 4755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4765c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner else if (c == '0') { 4775c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner padZero = 1; 4785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner continue; 4795c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4805c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner else if (c == '-') { 4815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner padLeft = 1; 4825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner continue; 4835c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner else if (c == ' ' || c == '+') { 4855c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner sign = c; 4865c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner continue; 4875c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 4895c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* parse field width */ 4925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if ((c >= '0' && c <= '9')) { 4935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn --; 4945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner width = (int)parse_decimal(format, &nn); 4955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 4965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* parse precision */ 4995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == '.') { 5005c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner prec = (int)parse_decimal(format, &nn); 5015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 5025c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5045c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* length modifier */ 5055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner switch (c) { 5065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'h': 5075c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(short); 5085c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (format[nn] == 'h') { 5095c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(char); 5105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn += 1; 5115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 5135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 5145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'l': 5155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(long); 5165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (format[nn] == 'l') { 5175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(long long); 5185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn += 1; 5195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 5215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 5225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'z': 5235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(size_t); 5245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 5255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 5265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 't': 5275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(ptrdiff_t); 5285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 5295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 5305c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner default: 5315c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ; 5325c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5335c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5345c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* conversion specifier */ 5355c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == 's') { 5365c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* string */ 5375c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner str = va_arg(args, const char*); 5385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } else if (c == 'c') { 5395c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* character */ 5405c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* NOTE: char is promoted to int when passed through the stack */ 5415c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[0] = (char) va_arg(args, int); 5425c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[1] = '\0'; 5435c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner str = buffer; 5445c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } else if (c == 'p') { 545ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden uint64_t value = (uintptr_t) va_arg(args, void*); 5465c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[0] = '0'; 5475c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[1] = 'x'; 5485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner format_hex(buffer + 2, sizeof buffer-2, value, 0); 5495c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner str = buffer; 5505c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } else { 5515c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* integers - first read value from stack */ 5525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner uint64_t value; 5535c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int isSigned = (c == 'd' || c == 'i' || c == 'o'); 5545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5555c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* NOTE: int8_t and int16_t are promoted to int when passed 5565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * through the stack 5575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 5585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner switch (bytelen) { 5595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 1: value = (uint8_t) va_arg(args, int); break; 5605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 2: value = (uint16_t) va_arg(args, int); break; 5615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 4: value = va_arg(args, uint32_t); break; 5625c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 8: value = va_arg(args, uint64_t); break; 5635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner default: return; /* should not happen */ 5645c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5655c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* sign extension, if needed */ 5675c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (isSigned) { 5685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int shift = 64 - 8*bytelen; 5695c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner value = (uint64_t)(((int64_t)(value << shift)) >> shift); 5705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5715c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5725c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* format the number properly into our buffer */ 5735c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner switch (c) { 5745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'i': case 'd': 5755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner format_integer(buffer, sizeof buffer, value, 10, isSigned); 5765c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 5775c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'o': 5785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner format_integer(buffer, sizeof buffer, value, 8, isSigned); 5795c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 5805c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'x': case 'X': 5815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner format_hex(buffer, sizeof buffer, value, (c == 'X')); 5825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 5835c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner default: 5845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[0] = '\0'; 5855c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5865c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* then point to it */ 5875c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner str = buffer; 5885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5895c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* if we are here, 'str' points to the content that must be 5915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * outputted. handle padding and alignment now */ 5925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner slen = strlen(str); 5945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (slen < width && !padLeft) { 5965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char padChar = padZero ? '0' : ' '; 5975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send_repeat(o, padChar, width - slen); 5985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6005c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send(o, str, slen); 6015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6025c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (slen < width && padLeft) { 6035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char padChar = padZero ? '0' : ' '; 6045c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send_repeat(o, padChar, width - slen); 6055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 6065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 6075c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 6085c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6095c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#ifdef UNIT_TESTS 6115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <stdio.h> 6135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic int gFails = 0; 6155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#define MARGIN 40 6175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#define UTEST_CHECK(condition,message) \ 6195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \ 6205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (!(condition)) { \ 6215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner printf("KO\n"); \ 6225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner gFails += 1; \ 6235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } else { \ 6245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner printf("ok\n"); \ 6255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 6265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 6285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerutest_BufOut(void) 6295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 6305c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char buffer[16]; 6315c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner BufOut bo[1]; 6325c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner Out* out; 6335c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int ret; 6345c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6355c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[0] = '1'; 6365c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out = buf_out_init(bo, buffer, sizeof buffer); 6375c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner UTEST_CHECK(buffer[0] == '\0', "buf_out_init clears initial byte"); 6385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send(out, "abc", 3); 6395c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner UTEST_CHECK(!memcmp(buffer, "abc", 4), "out_send() works with BufOut"); 6405c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send_repeat(out, 'X', 4); 6415c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner UTEST_CHECK(!memcmp(buffer, "abcXXXX", 8), "out_send_repeat() works with BufOut"); 6425c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[sizeof buffer-1] = 'x'; 6435c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send_repeat(out, 'Y', 2*sizeof(buffer)); 6445c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner UTEST_CHECK(buffer[sizeof buffer-1] == '\0', "overflows always zero-terminates"); 6455c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6465c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out = buf_out_init(bo, buffer, sizeof buffer); 6475c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send_repeat(out, 'X', 2*sizeof(buffer)); 6485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ret = buf_out_length(bo); 6495c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner UTEST_CHECK(ret == 2*sizeof(buffer), "correct size returned on overflow"); 6505c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 6515c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 6535c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerutest_expect(const char* result, const char* format, ...) 6545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 6555c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_list args; 6565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner BufOut bo[1]; 6575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char buffer[256]; 6585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner Out* out = buf_out_init(bo, buffer, sizeof buffer); 6595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner printf("Checking %-*s: ", MARGIN, format); fflush(stdout); 6615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_start(args, format); 6625c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_vformat(out, format, args); 6635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_end(args); 6645c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6655c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (strcmp(result, buffer)) { 6665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner printf("KO. got '%s' expecting '%s'\n", buffer, result); 6675c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner gFails += 1; 6685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } else { 6695c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner printf("ok. got '%s'\n", result); 6705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 6715c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 6725c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6735c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerint main(void) 6745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 6755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_BufOut(); 6765c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("", ""); 6775c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("a", "a"); 6785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("01234", "01234", ""); 6795c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("01234", "%s", "01234"); 6805c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("aabbcc", "aa%scc", "bb"); 6815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("a", "%c", 'a'); 6825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("1234", "%d", 1234); 6835c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("-8123", "%d", -8123); 6845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("16", "%hd", 0x7fff0010); 6855c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("16", "%hhd", 0x7fffff10); 686ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden utest_expect("68719476736", "%lld", 0x1000000000LL); 6875c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("70000", "%ld", 70000); 6885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("0xb0001234", "%p", (void*)0xb0001234); 6895c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("12ab", "%x", 0x12ab); 6905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("12AB", "%X", 0x12ab); 6915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("00123456", "%08x", 0x123456); 6925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("01234", "0%d", 1234); 6935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect(" 1234", "%5d", 1234); 6945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("01234", "%05d", 1234); 6955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect(" 1234", "%8d", 1234); 6965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("1234 ", "%-8d", 1234); 6975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("abcdef ", "%-11s", "abcdef"); 6985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("something:1234", "%s:%d", "something", 1234); 699ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden utest_expect("005:5:05", "%03d:%d:%02d", 5, 5, 5); 700ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden utest_expect("5,0x0", "%d,%p", 5, NULL); 701ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden utest_expect("68719476736,6,7,8", "%lld,%d,%d,%d", 0x1000000000LL, 6, 7, 8); 7025c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return gFails != 0; 7035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 7045c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 7055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#endif /* UNIT_TESTS */ 706