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 175166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turner/* The pthread implementation uses snprintf(). If we define it here, we 176166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turner * avoid pulling the stdio vfprintf() implementation into the linker 177166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turner * saving about 19KB of machine code. 178166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turner */ 179166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turnerint 180166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turnersnprintf(char* buff, size_t bufsize, const char* format, ...) 181166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turner{ 182166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turner va_list args; 183166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turner int ret; 184166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turner va_start(args, format); 185166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turner ret = vsnprintf(buff, bufsize, format, args); 186166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turner va_end(args); 187166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turner return ret; 188166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turner} 189166b7dbd4aa143fc22f61c64dae1219a910f1a6eDavid 'Digit' Turner 1905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#if LINKER_DEBUG 1915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#if !LINKER_DEBUG_TO_LOG 1935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/*** File descriptor output 1955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ***/ 1965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnertypedef struct { 1985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner Out out[1]; 1995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int fd; 2005c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int total; 2015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} FdOut; 2025c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 2045c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerfd_out_send(void *opaque, const char *data, int len) 2055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 2065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner FdOut *fdo = opaque; 2075c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2085c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (len < 0) 2095c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner len = strlen(data); 2105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner while (len > 0) { 2125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int ret = write(fdo->fd, data, len); 2135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (ret < 0) { 2145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (errno == EINTR) 2155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner continue; 2165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 2175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 2185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner data += ret; 2195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner len -= ret; 2205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner fdo->total += ret; 2215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 2225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 2235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic Out* 2255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerfd_out_init(FdOut *fdo, int fd) 2265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 2275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner fdo->out->opaque = fdo; 2285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner fdo->out->send = fd_out_send; 2295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner fdo->fd = fd; 2305c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner fdo->total = 0; 2315c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2325c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return fdo->out; 2335c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 2345c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2355c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic int 2365c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerfd_out_length(FdOut *fdo) 2375c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 2385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return fdo->total; 2395c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 2405c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2415c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2425c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerint 2435c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerformat_fd(int fd, const char *format, ...) 2445c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 2455c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner FdOut fdo; 2465c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner Out* out; 2475c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_list args; 2485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2495c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out = fd_out_init(&fdo, fd); 2505c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (out == NULL) 2515c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return 0; 2525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2535c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_start(args, format); 2545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_vformat(out, format, args); 2555c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_end(args); 2565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return fd_out_length(&fdo); 2585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 2595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#else /* LINKER_DEBUG_TO_LOG */ 2615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2625c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/*** Log output 2635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ***/ 2645c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2655c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* We need our own version of __libc_android_log_vprint, otherwise 2665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * the log output is completely broken. Probably due to the fact 2675c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * that the C library is not initialized yet. 2685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * 2695c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * You can test that by setting CUSTOM_LOG_VPRINT to 0 2705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 2715c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#define CUSTOM_LOG_VPRINT 1 2725c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2735c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#if CUSTOM_LOG_VPRINT 2745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <unistd.h> 2765c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <fcntl.h> 2775c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <sys/uio.h> 2785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2795c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic int log_vprint(int prio, const char *tag, const char *fmt, va_list args) 2805c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 2815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char buf[1024]; 2825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int result; 2835c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner static int log_fd = -1; 2845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2855c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner result = vformat_buffer(buf, sizeof buf, fmt, args); 2865c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2875c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (log_fd < 0) { 2885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner log_fd = open("/dev/log/main", O_WRONLY); 2895c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (log_fd < 0) 2905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return result; 2915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 2925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner { 2945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ssize_t ret; 2955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner struct iovec vec[3]; 2965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner vec[0].iov_base = (unsigned char *) &prio; 2985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner vec[0].iov_len = 1; 2995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner vec[1].iov_base = (void *) tag; 3005c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner vec[1].iov_len = strlen(tag) + 1; 3015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner vec[2].iov_base = (void *) buf; 3025c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner vec[2].iov_len = strlen(buf) + 1; 3035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3045c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner do { 3055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ret = writev(log_fd, vec, 3); 3065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } while ((ret < 0) && (errno == EINTR)); 3075c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3085c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return result; 3095c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 3105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#define __libc_android_log_vprint log_vprint 3125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#else /* !CUSTOM_LOG_VPRINT */ 3145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3154688279db5dcc4004941e7f133c4a1c3617d842cElliott Hughesextern "C" int __libc_android_log_vprint(int prio, const char* tag, const char* format, va_list ap); 3165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#endif /* !CUSTOM_LOG_VPRINT */ 3185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerint 3205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerformat_log(int prio, const char *tag, const char *format, ...) 3215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 3225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int ret; 3235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_list args; 3245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_start(args, format); 3255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ret = __libc_android_log_vprint(prio, tag, format, args); 3265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_end(args); 3275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return ret; 3285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 3295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3305c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#endif /* LINKER_DEBUG_TO_LOG */ 3315c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3325c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#endif /* LINKER_DEBUG */ 3335c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3345c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/*** formatted output implementation 3355c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ***/ 3365c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3375c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* Parse a decimal string from 'format + *ppos', 3385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * return the value, and writes the new position past 3395c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * the decimal string in '*ppos' on exit. 3405c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * 3415c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * NOTE: Does *not* handle a sign prefix. 3425c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 3435c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic unsigned 3445c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerparse_decimal(const char *format, int *ppos) 3455c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 3465c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner const char* p = format + *ppos; 3475c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner unsigned result = 0; 3485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3495c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner for (;;) { 3505c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int ch = *p; 3515c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner unsigned d = (unsigned)(ch - '0'); 3525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3535c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (d >= 10U) 3545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 3555c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner result = result*10 + d; 3575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner p++; 3585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner *ppos = p - format; 3605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return result; 3615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 3625c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* write an octal/decimal/number into a bounded buffer. 3645c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * assumes that bufsize > 0, and 'digits' is a string of 3655c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * digits of at least 'base' values. 3665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 3675c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 3685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerformat_number(char *buffer, size_t bufsize, uint64_t value, int base, const char *digits) 3695c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 3705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char *pos = buffer; 3715c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char *end = buffer + bufsize - 1; 3725c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3735c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* generate digit string in reverse order */ 3745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner while (value) { 3755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner unsigned d = value % base; 3765c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner value /= base; 3775c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (pos < end) { 3785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner *pos++ = digits[d]; 3795c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3805c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* special case for 0 */ 3835c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (pos == buffer) { 3845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (pos < end) { 3855c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner *pos++ = '0'; 3865c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3875c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner pos[0] = '\0'; 3895c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* now reverse digit string in-place */ 3915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner end = pos - 1; 3925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner pos = buffer; 3935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner while (pos < end) { 3945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int ch = pos[0]; 3955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner pos[0] = end[0]; 3965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner end[0] = (char) ch; 3975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner pos++; 3985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner end--; 3995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4005c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 4015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4025c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */ 4035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 4045c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerformat_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned) 4055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 4065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (isSigned && (int64_t)value < 0) { 4075c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[0] = '-'; 4085c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer += 1; 4095c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffsize -= 1; 4105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner value = (uint64_t)(-(int64_t)value); 4115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner format_number(buffer, buffsize, value, base, "0123456789"); 4145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 4155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* Write an hexadecimal into a buffer, isCap is true for capital alphas. 4175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * Assumes bufsize > 2 */ 4185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 4195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerformat_hex(char *buffer, size_t buffsize, uint64_t value, int isCap) 4205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 4215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner const char *digits = isCap ? "0123456789ABCDEF" : "0123456789abcdef"; 4225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner format_number(buffer, buffsize, value, 16, digits); 4245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 4255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* Perform formatted output to an output target 'o' */ 4285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 4295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerout_vformat(Out *o, const char *format, va_list args) 4305c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 431ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int nn = 0; 4325c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4335c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner for (;;) { 434ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int mm; 435ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int padZero = 0; 436ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int padLeft = 0; 437ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden char sign = '\0'; 438ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int width = -1; 439ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int prec = -1; 440ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden size_t bytelen = sizeof(int); 441ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden const char* str; 442ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden int slen; 443ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden char buffer[32]; /* temporary buffer used to format numbers */ 444ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden 4455c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char c; 4465c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4475c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* first, find all characters that are not 0 or '%' */ 4485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* then send them to the output directly */ 4495c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner mm = nn; 4505c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner do { 4515c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[mm]; 4525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == '\0' || c == '%') 4535c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 4545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner mm++; 4555c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } while (1); 4565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (mm > nn) { 4585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send(o, format+nn, mm-nn); 4595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn = mm; 4605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4625c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* is this it ? then exit */ 4635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == '\0') 4645c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 4655c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* nope, we are at a '%' modifier */ 4675c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn++; // skip it 4685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4695c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* parse flags */ 4705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner for (;;) { 4715c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 4725c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == '\0') { /* single trailing '%' ? */ 4735c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = '%'; 4745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send(o, &c, 1); 4755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return; 4765c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4775c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner else if (c == '0') { 4785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner padZero = 1; 4795c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner continue; 4805c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner else if (c == '-') { 4825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner padLeft = 1; 4835c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner continue; 4845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4855c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner else if (c == ' ' || c == '+') { 4865c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner sign = c; 4875c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner continue; 4885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4895c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 4905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* parse field width */ 4935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if ((c >= '0' && c <= '9')) { 4945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn --; 4955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner width = (int)parse_decimal(format, &nn); 4965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 4975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 4995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* parse precision */ 5005c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == '.') { 5015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner prec = (int)parse_decimal(format, &nn); 5025c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 5035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5045c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* length modifier */ 5065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner switch (c) { 5075c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'h': 5085c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(short); 5095c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (format[nn] == 'h') { 5105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(char); 5115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn += 1; 5125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 5145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 5155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'l': 5165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(long); 5175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (format[nn] == 'l') { 5185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(long long); 5195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner nn += 1; 5205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 5225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 5235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'z': 5245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(size_t); 5255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 5265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 5275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 't': 5285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner bytelen = sizeof(ptrdiff_t); 5295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner c = format[nn++]; 5305c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 5315c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner default: 5325c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ; 5335c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5345c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5355c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* conversion specifier */ 5365c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (c == 's') { 5375c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* string */ 5385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner str = va_arg(args, const char*); 5395c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } else if (c == 'c') { 5405c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* character */ 5415c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* NOTE: char is promoted to int when passed through the stack */ 5425c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[0] = (char) va_arg(args, int); 5435c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[1] = '\0'; 5445c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner str = buffer; 5455c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } else if (c == 'p') { 546ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden uint64_t value = (uintptr_t) va_arg(args, void*); 5475c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[0] = '0'; 5485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[1] = 'x'; 5495c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner format_hex(buffer + 2, sizeof buffer-2, value, 0); 5505c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner str = buffer; 5515c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } else { 5525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* integers - first read value from stack */ 5535c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner uint64_t value; 5545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int isSigned = (c == 'd' || c == 'i' || c == 'o'); 5555c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* NOTE: int8_t and int16_t are promoted to int when passed 5575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * through the stack 5585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 5595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner switch (bytelen) { 5605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 1: value = (uint8_t) va_arg(args, int); break; 5615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 2: value = (uint16_t) va_arg(args, int); break; 5625c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 4: value = va_arg(args, uint32_t); break; 5635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 8: value = va_arg(args, uint64_t); break; 5645c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner default: return; /* should not happen */ 5655c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5675c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* sign extension, if needed */ 5685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (isSigned) { 5695c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int shift = 64 - 8*bytelen; 5705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner value = (uint64_t)(((int64_t)(value << shift)) >> shift); 5715c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5725c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5735c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* format the number properly into our buffer */ 5745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner switch (c) { 5755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'i': case 'd': 5765c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner format_integer(buffer, sizeof buffer, value, 10, isSigned); 5775c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 5785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'o': 5795c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner format_integer(buffer, sizeof buffer, value, 8, isSigned); 5805c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 5815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner case 'x': case 'X': 5825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner format_hex(buffer, sizeof buffer, value, (c == 'X')); 5835c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner break; 5845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner default: 5855c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[0] = '\0'; 5865c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5875c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* then point to it */ 5885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner str = buffer; 5895c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 5905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner /* if we are here, 'str' points to the content that must be 5925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * outputted. handle padding and alignment now */ 5935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner slen = strlen(str); 5955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 5965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (slen < width && !padLeft) { 5975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char padChar = padZero ? '0' : ' '; 5985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send_repeat(o, padChar, width - slen); 5995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 6005c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send(o, str, slen); 6025c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (slen < width && padLeft) { 6045c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char padChar = padZero ? '0' : ' '; 6055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send_repeat(o, padChar, width - slen); 6065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 6075c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 6085c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 6095c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#ifdef UNIT_TESTS 6125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <stdio.h> 6145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic int gFails = 0; 6165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#define MARGIN 40 6185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#define UTEST_CHECK(condition,message) \ 6205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \ 6215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (!(condition)) { \ 6225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner printf("KO\n"); \ 6235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner gFails += 1; \ 6245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } else { \ 6255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner printf("ok\n"); \ 6265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 6275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 6295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerutest_BufOut(void) 6305c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 6315c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char buffer[16]; 6325c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner BufOut bo[1]; 6335c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner Out* out; 6345c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner int ret; 6355c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6365c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[0] = '1'; 6375c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out = buf_out_init(bo, buffer, sizeof buffer); 6385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner UTEST_CHECK(buffer[0] == '\0', "buf_out_init clears initial byte"); 6395c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send(out, "abc", 3); 6405c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner UTEST_CHECK(!memcmp(buffer, "abc", 4), "out_send() works with BufOut"); 6415c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send_repeat(out, 'X', 4); 6425c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner UTEST_CHECK(!memcmp(buffer, "abcXXXX", 8), "out_send_repeat() works with BufOut"); 6435c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner buffer[sizeof buffer-1] = 'x'; 6445c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send_repeat(out, 'Y', 2*sizeof(buffer)); 6455c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner UTEST_CHECK(buffer[sizeof buffer-1] == '\0', "overflows always zero-terminates"); 6465c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6475c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out = buf_out_init(bo, buffer, sizeof buffer); 6485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_send_repeat(out, 'X', 2*sizeof(buffer)); 6495c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ret = buf_out_length(bo); 6505c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner UTEST_CHECK(ret == 2*sizeof(buffer), "correct size returned on overflow"); 6515c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 6525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6535c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerstatic void 6545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerutest_expect(const char* result, const char* format, ...) 6555c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 6565c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_list args; 6575c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner BufOut bo[1]; 6585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner char buffer[256]; 6595c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner Out* out = buf_out_init(bo, buffer, sizeof buffer); 6605c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner printf("Checking %-*s: ", MARGIN, format); fflush(stdout); 6625c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_start(args, format); 6635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner out_vformat(out, format, args); 6645c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner va_end(args); 6655c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner if (strcmp(result, buffer)) { 6675c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner printf("KO. got '%s' expecting '%s'\n", buffer, result); 6685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner gFails += 1; 6695c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } else { 6705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner printf("ok. got '%s'\n", result); 6715c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 6725c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 6735c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 6745c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turnerint main(void) 6755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner{ 6765c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_BufOut(); 6775c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("", ""); 6785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("a", "a"); 6795c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("01234", "01234", ""); 6805c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("01234", "%s", "01234"); 6815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("aabbcc", "aa%scc", "bb"); 6825c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("a", "%c", 'a'); 6835c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("1234", "%d", 1234); 6845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("-8123", "%d", -8123); 6855c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("16", "%hd", 0x7fff0010); 6865c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("16", "%hhd", 0x7fffff10); 687ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden utest_expect("68719476736", "%lld", 0x1000000000LL); 6885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("70000", "%ld", 70000); 6895c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("0xb0001234", "%p", (void*)0xb0001234); 6905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("12ab", "%x", 0x12ab); 6915c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("12AB", "%X", 0x12ab); 6925c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("00123456", "%08x", 0x123456); 6935c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("01234", "0%d", 1234); 6945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect(" 1234", "%5d", 1234); 6955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("01234", "%05d", 1234); 6965c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect(" 1234", "%8d", 1234); 6975c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("1234 ", "%-8d", 1234); 6985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("abcdef ", "%-11s", "abcdef"); 6995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner utest_expect("something:1234", "%s:%d", "something", 1234); 700ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden utest_expect("005:5:05", "%03d:%d:%02d", 5, 5, 5); 701ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden utest_expect("5,0x0", "%d,%p", 5, NULL); 702ec92af8fe5d28c74f3505932135b1b8f3fbaad00Andy McFadden utest_expect("68719476736,6,7,8", "%lld,%d,%d,%d", 0x1000000000LL, 6, 7, 8); 7035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner return gFails != 0; 7045c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 7055c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 7065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#endif /* UNIT_TESTS */ 707