diff --git a/pp_printf/COPYING b/pp_printf/COPYING new file mode 100644 index 0000000000000000000000000000000000000000..d511905c1647a1e311e8b20d5930a37a9c2531cd --- /dev/null +++ b/pp_printf/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/pp_printf/Makefile b/pp_printf/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f2ea212f084bf1adf4b658be48ed0a19b40e98f0 --- /dev/null +++ b/pp_printf/Makefile @@ -0,0 +1,44 @@ +# Alessandro Rubini for CERN, 2011 -- public domain + +AS = $(CROSS_COMPILE)as +LD = $(CROSS_COMPILE)ld +CC = $(CROSS_COMPILE)gcc +CPP = $(CC) -E +AR = $(CROSS_COMPILE)ar +NM = $(CROSS_COMPILE)nm +STRIP = $(CROSS_COMPILE)strip +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump + +CFLAGS += -I. -Os -ggdb -Wall + +obj-$(CONFIG_PRINTF_FULL) += vsprintf-full.o +obj-$(CONFIG_PRINTF_MINI) += vsprintf-mini.o +obj-$(CONFIG_PRINTF_NONE) += vsprintf-none.o +obj-$(CONFIG_PRINTF_XINT) += vsprintf-xint.o + +# set full as a default if nothing is selected +obj-y ?= vsprintf-full.o + +obj-y += printf.o + +# There is a static variable in pp-printf.c to accumulate stuff +CONFIG_PRINT_BUFSIZE ?= 256 + +CFLAGS += -DCONFIG_PRINT_BUFSIZE=$(CONFIG_PRINT_BUFSIZE) + +# Targets. You may want to make them different in your package + +all: pp-printf.o example-printf + +pp-printf.o: $(obj-y) + $(LD) -r $(obj-y) -o $@ + +example-printf: example-printf.c pp-printf.o + $(CC) $(CFLAGS) $^ -o $@ + +.c.o: + $(CC) -c $(CFLAGS) $< -o $@ + +clean: + rm -f *.o *~ example-printf \ No newline at end of file diff --git a/pp_printf/README b/pp_printf/README new file mode 100644 index 0000000000000000000000000000000000000000..9216b633ad4d42f81207fd65e7448ab4d194242e --- /dev/null +++ b/pp_printf/README @@ -0,0 +1,179 @@ + +This is the "poor programmer's" printf implementation. It is meant to +be used in small environments, like microcontrollers or soft +processors. Actually, that's where I needed it years ago and where +I'm still using it. + +It is a complete printf (it only misses the %[charset] feature, and +obviously floating point support). It relies on an external "puts" +function for the actual output; the full version also needs strnlen. +Unfortunately, the stdio puts adds a trailing newline (while most +embedded implementations do not). The sprintf function is included. + +The printf engine, vsprintf(), comes in four flavours: + +In summary: + + - the "full" version is a normal printf (GPL2, from older Linux kernel) + + - the "xint" version accepts all formats and prints hex and int only + + - the "mini" version accepts all formats but only prints hex (GPL2) + + - the "none" version accepts all formats and prints nothing (PD) + +The version you use can be selected at compile time, so you can +develop with a full-featured printf and install the minimal one in +production, saving a few kilobytes and still not loosing information +in messages. At the end I list compiled sizes for a few use cases. + +While I use this very code in several projects, the only example here +is a stupid main that prints something. You are expected to pick these +files and copy them to your projects, rather than use this "package" +as a system library. + + + The full implementation in detail + ================================= + +This comes from u-boot, which means that it is an earlier printf as +used in the Linux kernel. It is licensed according to the GNU GPL +version 2. It includes all formats and prefixes and so on. It is +clearly bugless because everybody is using it. + +It is selected at compile time by setting the make variable +"CONFIG_PRINTF_FULL" to "y". You can do that in the environment, +or use Kconfig in your application. + +(The Makefile selects this by default if you set nothing in the +environment or make variables) + +Example calls (example-printf.c): + + pp_printf("integer %5i %5i %05i\n", 1024, 666, 53); + pp_printf("octal %5o %5o %05o\n", 1024, 666, 53); + pp_printf("hex %5x %5x %05x\n", 1024, 666, 53); + pp_printf("HEX etc %5X %+5d %-5i\n", 1024, 666, 53); + pp_printf("char: %c string %s %5s %.5s\n", 65, "foo", "foo", + "verylongstring"); + +Result (as you see, format modifiers are respected): + + integer 1024 666 00053 + octal 2000 1232 00065 + hex 400 29a 00035 + HEX etc 400 +666 53 + char: A string foo foo veryl + +Footprint: 1500-3300 bytes, plus 100-400 bytes for the frontend. + + + The xint implementaion in detail + ================================ + +This prints correctly "%c", "%s", "%i", "%x". Formats "%u" and "%d" +are synonims of "%i", and "%p"is a synonim for "%x". No attributes +are supported, to keep size small. I personally dislike it, because it +not powerful enough nor low-level as real hacker's too should be. +However, it matches the requirement of some projects with a little +user interface, where the "full" code reveals too large and the "mini" +code is too unfair to the reader. To compile it and link the example, +please set "CONFIG_PRINTF_XINT=y" in your environment or Makefile. + +This is the result of the example. As expected, no size nor precision +directives are obeyed: + + integer 1024 666 53 + octal 2000 1232 65 + hex 400 29a 35 + HEX etc 400 666 53 + char: A string foo foo verylongstring + +Footprint: 250-700 bytes, plus 100-250 bytes for the frontend + + + The miminal implementaion in detail + =================================== + +It is derived from the full one. I left all format parsing intact, but +only print "%s" and "%c". Everything else is printed as hex numbers +like "<badc0ffe>". This means your 47 printed as "%03i" will be output +as "<0000002f>" instead of "047". Still, the standard format is +accepted without errors and no information is lost. + +I have made no checks nor reasoning about 32-bit vs 64-bit. I only +used it on 32-bit computers and never printed "long long". Now that it +is published, I have an incentive to do it, though. + +It is selected at compile time by setting CONFIG_PRINTF_MINI=y as a +make variable, possibly inherited by the environment. It is licensed +as GPL version 2 because it's derived from the full one -- I left the +parsing as I found in there. + +Result of example-printf (you can "make CONFIG_PRINTF_MINI=y): + + integer <00000400> <0000029a> <00000035> + octal <00000400> <0000029a> <00000035> + hex <00000400> <0000029a> <00000035> + HEX etc <00000400> <0000029a> <00000035> + char: A string foo foo verylongstring + +As promised, %c and %s is printed correctly, but without obeying the +format modifiers, but all integer value are printed in hex. + +Footprint: 200-600 bytes (usually less than 1k), plus 100-400 for the +frontend. + + + The empty implementation in detail + ================================== + +The empty implementation, called "none" to respect the 4-letter +pattern of "full" and "mini" doesn't parse any format. It simply +prints the format string and nothing more. This allows to keep the +most important messages, like the welcome string or a "Panic" string, +while saving code space. + +It is selected at compile time by setting CONFIG_PRINTF_NONE. + +Result of example-printf (you can "make CONFIG_PRINTF_MINI=y): + + integer %5i %5i %05i + octal %5o %5o %05o + hex %5x %5x %05x + HEX etc %5X %+5d %-5i + char: %c string %s %5s %.5s + +Footprint: 20-90 bytes, plus 100-400 for the frontend. + +If you want to remove all printf overhead in production, you should +use a preprocessor macro to completely kill the printf calls. This +would save you the parameter-passing overhead in the caller and all +the constant strings in .rodata. I don't support this in the package, +though, and I discourage from doing it, for the usual +preprocessor-related reasons. + + + Footprint of the various implementations + ======================================== + +This table excludes the static buffer (256 in .bss by default) and +only lists the code size (command "size", column "text"), compiled +with -Os as for this Makefile. + +printf.o is the frontend and is linked in all four configurations, +the other ones are exclusive one another: + + printf.o full xint mini none + + x86, gcc-4.4.5 87 1715 300 258 29 + x86-64, gcc-4.4.5 418 2325 482 433 70 + x86, gcc-4.6.2 255 2210 380 330 89 + arm, gcc-4.2.2 156 2408 464 356 48 + arm, gcc-4.5.2 128 2235 445 353 32 + arm, gcc-4.5.2 thumb2 80 1443 253 209 20 + lm32, gcc-4.5.3 196 3228 680 576 36 + mips, gcc-4.4.1 184 2616 616 504 72 + powerpc, gcc-4.4.1 328 2895 637 521 40 + coldfire, gcc-4.4.1 96 2025 331 257 32 + sh4, gcc-4.4.1 316 2152 464 408 28 diff --git a/pp_printf/example-printf.c b/pp_printf/example-printf.c new file mode 100644 index 0000000000000000000000000000000000000000..4b375b7eebd62a4f3e3bfe6a529bf8035dc4abb4 --- /dev/null +++ b/pp_printf/example-printf.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <pp-printf.h> + +int main(int argc, char **argv) +{ + pp_printf("integer %5i %5i %05i\n", 1024, 666, 53); + pp_printf("octal %5o %5o %05o\n", 1024, 666, 53); + pp_printf("hex %5x %5x %05x\n", 1024, 666, 53); + pp_printf("HEX etc %5X %+5d %-5i\n", 1024, 666, 53); + pp_printf("char: %c string %s %5s %.5s\n", 65, "foo", "foo", + "verylongstring"); + return 0; +} diff --git a/pp_printf/pp-printf.h b/pp_printf/pp-printf.h new file mode 100644 index 0000000000000000000000000000000000000000..30f715909f0ab8e4e1205c1269b0becdb4633356 --- /dev/null +++ b/pp_printf/pp-printf.h @@ -0,0 +1,17 @@ +#include <stdarg.h> + +extern int pp_printf(const char *fmt, ...) + __attribute__((format(printf,1,2))); + +extern int pp_sprintf(char *s, const char *fmt, ...) + __attribute__((format(printf,2,3))); + +extern int pp_vprintf(const char *fmt, va_list args); + +extern int pp_vsprintf(char *buf, const char *, va_list) + __attribute__ ((format (printf, 2, 0))); + +/* This is what we rely on for output */ +extern int puts(const char *s); + + diff --git a/pp_printf/printf.c b/pp_printf/printf.c new file mode 100644 index 0000000000000000000000000000000000000000..ec5b96e97610633f2d2d3d252d327dac14baa21a --- /dev/null +++ b/pp_printf/printf.c @@ -0,0 +1,43 @@ +/* + * Basic printf based on vprintf based on vsprintf + * + * Alessandro Rubini for CERN, 2011 -- public domain + * (please note that the vsprintf is not public domain but GPL) + */ +#include <stdarg.h> +#include <pp-printf.h> + +static char print_buf[CONFIG_PRINT_BUFSIZE]; + +int pp_vprintf(const char *fmt, va_list args) +{ + int ret; + + ret = pp_vsprintf(print_buf, fmt, args); + puts(print_buf); + return ret; +} + +int pp_sprintf(char *s, const char *fmt, ...) +{ + va_list args; + int ret; + + va_start(args, fmt); + ret = pp_vsprintf(s, fmt, args); + va_end(args); + return ret; +} + + +int pp_printf(const char *fmt, ...) +{ + va_list args; + int ret; + + va_start(args, fmt); + ret = pp_vprintf(fmt, args); + va_end(args); + + return ret; +} diff --git a/pp_printf/vsprintf-full.c b/pp_printf/vsprintf-full.c new file mode 100644 index 0000000000000000000000000000000000000000..b8c15f42d75af8c301983bee1c6a804eb7f8a45f --- /dev/null +++ b/pp_printf/vsprintf-full.c @@ -0,0 +1,591 @@ +/* + * linux/lib/vsprintf.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * GNU GPL version 2 + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +/* Retrieved from u-boot on 2010-02, changed some stuff (ARub) */ +#include <stdarg.h> +#include <stdint.h> +#include <string.h> + +/* BEGIN OF HACKS */ +#include <pp-printf.h> + +/* <ctype.h> */ +static inline int isdigit(int c) +{ + return c >= '0' && c <= '9'; +} + +static inline int islower(int c) +{ + return c >= 'a' && c <= 'z'; +} + +static inline int isupper(int c) +{ + return c >= 'A' && c <= 'Z'; +} + +static inline int isalpha(int c) +{ + return islower(c) || isupper(c); +} + +static inline int isalnum(int c) +{ + return isalpha(c) || isdigit(c); +} + +/* <linux/types.h> -- but if we typedef we get redefined type when hosted */ +#define u8 uint8_t +#define size_t unsigned long +#define ptrdiff_t unsigned long + +#define noinline __attribute__((noinline)) +/* END OF HACKS */ + +const char hex_asc[] = "0123456789abcdef"; +#define hex_asc_lo(x) hex_asc[((x) & 0x0f)] +#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4] + +static inline char *pack_hex_byte(char *buf, u8 byte) +{ + *buf++ = hex_asc_hi(byte); + *buf++ = hex_asc_lo(byte); + return buf; +} + + +/* we use this so that we can do without the ctype library */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +/* Decimal conversion is by far the most typical, and is used + * for /proc and /sys data. This directly impacts e.g. top performance + * with many processes running. We optimize it for speed + * using code from + * http://www.cs.uiowa.edu/~jones/bcd/decimal.html + * (with permission from the author, Douglas W. Jones). */ + +/* Formats correctly any integer in [0,99999]. + * Outputs from one to five digits depending on input. + * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */ +static char* put_dec_trunc(char *buf, unsigned q) +{ + unsigned d3, d2, d1, d0; + d1 = (q>>4) & 0xf; + d2 = (q>>8) & 0xf; + d3 = (q>>12); + + d0 = 6*(d3 + d2 + d1) + (q & 0xf); + q = (d0 * 0xcd) >> 11; + d0 = d0 - 10*q; + *buf++ = d0 + '0'; /* least significant digit */ + d1 = q + 9*d3 + 5*d2 + d1; + if (d1 != 0) { + q = (d1 * 0xcd) >> 11; + d1 = d1 - 10*q; + *buf++ = d1 + '0'; /* next digit */ + + d2 = q + 2*d2; + if ((d2 != 0) || (d3 != 0)) { + q = (d2 * 0xd) >> 7; + d2 = d2 - 10*q; + *buf++ = d2 + '0'; /* next digit */ + + d3 = q + 4*d3; + if (d3 != 0) { + q = (d3 * 0xcd) >> 11; + d3 = d3 - 10*q; + *buf++ = d3 + '0'; /* next digit */ + if (q != 0) + *buf++ = q + '0'; /* most sign. digit */ + } + } + } + return buf; +} +/* Same with if's removed. Always emits five digits */ +static char* put_dec_full(char *buf, unsigned q) +{ + /* BTW, if q is in [0,9999], 8-bit ints will be enough, */ + /* but anyway, gcc produces better code with full-sized ints */ + unsigned d3, d2, d1, d0; + d1 = (q>>4) & 0xf; + d2 = (q>>8) & 0xf; + d3 = (q>>12); + + /* + * Possible ways to approx. divide by 10 + * gcc -O2 replaces multiply with shifts and adds + * (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386) + * (x * 0x67) >> 10: 1100111 + * (x * 0x34) >> 9: 110100 - same + * (x * 0x1a) >> 8: 11010 - same + * (x * 0x0d) >> 7: 1101 - same, shortest code (on i386) + */ + + d0 = 6*(d3 + d2 + d1) + (q & 0xf); + q = (d0 * 0xcd) >> 11; + d0 = d0 - 10*q; + *buf++ = d0 + '0'; + d1 = q + 9*d3 + 5*d2 + d1; + q = (d1 * 0xcd) >> 11; + d1 = d1 - 10*q; + *buf++ = d1 + '0'; + + d2 = q + 2*d2; + q = (d2 * 0xd) >> 7; + d2 = d2 - 10*q; + *buf++ = d2 + '0'; + + d3 = q + 4*d3; + q = (d3 * 0xcd) >> 11; /* - shorter code */ + /* q = (d3 * 0x67) >> 10; - would also work */ + d3 = d3 - 10*q; + *buf++ = d3 + '0'; + *buf++ = q + '0'; + return buf; +} +/* No inlining helps gcc to use registers better */ +static noinline char* put_dec(char *buf, unsigned long num) +{ + while (1) { + unsigned rem; + if (num < 100000) + return put_dec_trunc(buf, num); + rem = num % 100000; + num /= 100000; + buf = put_dec_full(buf, rem); + } +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SMALL 32 /* Must be 32 == 0x20 */ +#define SPECIAL 64 /* 0x */ + +static char *number(char *buf, unsigned long num, int base, int size, int precision, int type) +{ + /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ + static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ + + char tmp[66]; + char sign; + char locase; + int need_pfx = ((type & SPECIAL) && base != 10); + int i; + + /* locase = 0 or 0x20. ORing digits or letters with 'locase' + * produces same digits or (maybe lowercased) letters */ + locase = (type & SMALL); + if (type & LEFT) + type &= ~ZEROPAD; + sign = 0; + if (type & SIGN) { + if ((signed long) num < 0) { + sign = '-'; + num = - (signed long) num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (need_pfx) { + size--; + if (base == 16) + size--; + } + + /* generate full string in tmp[], in reverse order */ + i = 0; + if (num == 0) + tmp[i++] = '0'; + /* Generic code, for any base: + else do { + tmp[i++] = (digits[do_div(num,base)] | locase); + } while (num != 0); + */ + else if (base != 10) { /* 8 or 16 */ + int mask = base - 1; + int shift = 3; + if (base == 16) shift = 4; + do { + tmp[i++] = (digits[((unsigned char)num) & mask] | locase); + num >>= shift; + } while (num); + } else { /* base 10 */ + i = put_dec(tmp, num) - tmp; + } + + /* printing 100 using %2d gives "100", not "00" */ + if (i > precision) + precision = i; + /* leading space padding */ + size -= precision; + if (!(type & (ZEROPAD+LEFT))) + while(--size >= 0) + *buf++ = ' '; + /* sign */ + if (sign) + *buf++ = sign; + /* "0x" / "0" prefix */ + if (need_pfx) { + *buf++ = '0'; + if (base == 16) + *buf++ = ('X' | locase); + } + /* zero or space padding */ + if (!(type & LEFT)) { + char c = (type & ZEROPAD) ? '0' : ' '; + while (--size >= 0) + *buf++ = c; + } + /* hmm even more zero padding? */ + while (i <= --precision) + *buf++ = '0'; + /* actual digits of result */ + while (--i >= 0) + *buf++ = tmp[i]; + /* trailing space padding */ + while (--size >= 0) + *buf++ = ' '; + return buf; +} + +static char *string(char *buf, char *s, int field_width, int precision, int flags) +{ + int len, i; + + if (s == 0) + s = "<NULL>"; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *buf++ = ' '; + for (i = 0; i < len; ++i) + *buf++ = *s++; + while (len < field_width--) + *buf++ = ' '; + return buf; +} + +#ifdef CONFIG_CMD_NET +static char *mac_address_string(char *buf, u8 *addr, int field_width, + int precision, int flags) +{ + char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */ + char *p = mac_addr; + int i; + + for (i = 0; i < 6; i++) { + p = pack_hex_byte(p, addr[i]); + if (!(flags & SPECIAL) && i != 5) + *p++ = ':'; + } + *p = '\0'; + + return string(buf, mac_addr, field_width, precision, flags & ~SPECIAL); +} + +static char *ip6_addr_string(char *buf, u8 *addr, int field_width, + int precision, int flags) +{ + char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */ + char *p = ip6_addr; + int i; + + for (i = 0; i < 8; i++) { + p = pack_hex_byte(p, addr[2 * i]); + p = pack_hex_byte(p, addr[2 * i + 1]); + if (!(flags & SPECIAL) && i != 7) + *p++ = ':'; + } + *p = '\0'; + + return string(buf, ip6_addr, field_width, precision, flags & ~SPECIAL); +} + +static char *ip4_addr_string(char *buf, u8 *addr, int field_width, + int precision, int flags) +{ + char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */ + char temp[3]; /* hold each IP quad in reverse order */ + char *p = ip4_addr; + int i, digits; + + for (i = 0; i < 4; i++) { + digits = put_dec_trunc(temp, addr[i]) - temp; + /* reverse the digits in the quad */ + while (digits--) + *p++ = temp[digits]; + if (i != 3) + *p++ = '.'; + } + *p = '\0'; + + return string(buf, ip4_addr, field_width, precision, flags & ~SPECIAL); +} +#endif + +/* + * Show a '%p' thing. A kernel extension is that the '%p' is followed + * by an extra set of alphanumeric characters that are extended format + * specifiers. + * + * Right now we handle: + * + * - 'M' For a 6-byte MAC address, it prints the address in the + * usual colon-separated hex notation + * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated + * decimal for v4 and colon separated network-order 16 bit hex for v6) + * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is + * currently the same + * + * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 + * function pointers are really function descriptors, which contain a + * pointer to the real address. + */ +static char *pointer(const char *fmt, char *buf, void *ptr, int field_width, int precision, int flags) +{ + if (!ptr) + return string(buf, "(null)", field_width, precision, flags); + +#ifdef CONFIG_CMD_NET + switch (*fmt) { + case 'm': + flags |= SPECIAL; + /* Fallthrough */ + case 'M': + return mac_address_string(buf, ptr, field_width, precision, flags); + case 'i': + flags |= SPECIAL; + /* Fallthrough */ + case 'I': + if (fmt[1] == '6') + return ip6_addr_string(buf, ptr, field_width, precision, flags); + if (fmt[1] == '4') + return ip4_addr_string(buf, ptr, field_width, precision, flags); + flags &= ~SPECIAL; + break; + } +#endif + flags |= SMALL; + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + return number(buf, (unsigned long) ptr, 16, field_width, precision, flags); +} + +/** + * vsprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @fmt: The format string to use + * @args: Arguments for the format string + * + * This function follows C99 vsprintf, but has some extensions: + * %pS output the name of a text symbol + * %pF output the name of a function pointer + * %pR output the address range in a struct resource + * + * The function returns the number of characters written + * into @buf. + * + * Call this function if you are already dealing with a va_list. + * You probably want sprintf() instead. + */ +int pp_vsprintf(char *buf, const char *fmt, va_list args) +{ + unsigned long num; + int base; + char *str; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + /* 'z' support added 23/7/1999 S.H. */ + /* 'z' changed to 'Z' --davidm 1/25/99 */ + /* 't' added for ptrdiff_t */ + + str = buf; + + for (; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || + *fmt == 'Z' || *fmt == 'z' || *fmt == 't') { + qualifier = *fmt; + ++fmt; + if (qualifier == 'l' && *fmt == 'l') { + qualifier = 'L'; + ++fmt; + } + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + str = string(str, va_arg(args, char *), field_width, precision, flags); + continue; + + case 'p': + str = pointer(fmt+1, str, + va_arg(args, void *), + field_width, precision, flags); + /* Skip all alphanumeric pointer suffixes */ + while (isalnum(fmt[1])) + fmt++; + continue; + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'x': + flags |= SMALL; + case 'X': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } +#ifdef CONFIG_SYS_64BIT_VSPRINTF + if (qualifier == 'L') /* "quad" for 64 bit variables */ + num = va_arg(args, unsigned long long); + else +#endif + if (qualifier == 'l') { + num = va_arg(args, unsigned long); + if (flags & SIGN) + num = (signed long) num; + } else if (qualifier == 'Z' || qualifier == 'z') { + num = va_arg(args, size_t); + } else if (qualifier == 't') { + num = va_arg(args, ptrdiff_t); + } else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (signed short) num; + } else { + num = va_arg(args, unsigned int); + if (flags & SIGN) + num = (signed int) num; + } + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str-buf; +} diff --git a/pp_printf/vsprintf-mini.c b/pp_printf/vsprintf-mini.c new file mode 100644 index 0000000000000000000000000000000000000000..d68c8488457a3b57e0f33ec2fda0752f4129b889 --- /dev/null +++ b/pp_printf/vsprintf-mini.c @@ -0,0 +1,69 @@ +#include <stdarg.h> +/* + * minimal vsprintf: only %s and hex values + * Alessandro Rubini 2010, based on code in u-boot (from older Linux) + * GNU GPL version 2. + */ +int pp_vsprintf(char *buf, const char *fmt, va_list args) +{ + int i, j; + static char hex[] = "0123456789abcdef"; + char *s; + char *str = buf; + + for (; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + repeat: + fmt++; /* Skip '%' initially, other stuff later */ + + /* Skip the complete format string */ + switch(*fmt) { + case '\0': + goto ret; + case '*': + /* should be precision, just eat it */ + i = va_arg(args, int); + /* fall through: discard unknown stuff */ + default: + goto repeat; + + /* Special cases for conversions */ + + case 'c': /* char: supported */ + *str++ = (unsigned char) va_arg(args, int); + break; + case 's': /* string: supported */ + s = va_arg(args, char *); + while (*s) + *str++ = *s++; + break; + case 'n': /* number-thus-far: not supported */ + break; + case '%': /* supported */ + *str++ = '%'; + break; + + /* all integer (and pointer) are printed as <%08x> */ + case 'o': + case 'x': + case 'X': + case 'd': + case 'i': + case 'u': + case 'p': + i = va_arg(args, int); + *str++ = '<'; + for (j = 28; j >= 0; j -= 4) + *str++ = hex[(i>>j)&0xf]; + *str++ = '>'; + break; + } + } + ret: + *str = '\0'; + return str - buf; +} diff --git a/pp_printf/vsprintf-none.c b/pp_printf/vsprintf-none.c new file mode 100644 index 0000000000000000000000000000000000000000..399ad514ce0be9d0d6fccc2726ead96f32c47be5 --- /dev/null +++ b/pp_printf/vsprintf-none.c @@ -0,0 +1,13 @@ +#include <stdarg.h> +#include <pp-printf.h> +/* + * empty vsprintf: only the format string. Public domain + */ +int pp_vsprintf(char *buf, const char *fmt, va_list args) +{ + char *str = buf; + + for (; *fmt ; ++fmt) + *str++ = *fmt; + return str - buf; +} diff --git a/pp_printf/vsprintf-xint.c b/pp_printf/vsprintf-xint.c new file mode 100644 index 0000000000000000000000000000000000000000..951706793cc5a26d6e9664d64d2b57d4f8114508 --- /dev/null +++ b/pp_printf/vsprintf-xint.c @@ -0,0 +1,90 @@ +/* + * vsprintf-ugly: a possible free-software replacement for mprintf + * + * public domain + */ +#include <stdarg.h> +#include <stdint.h> + +static const char hex[] = "0123456789abcdef"; + +static int number(char *out, int value, int base) +{ + char tmp[16]; + int i = 16, ret; + + /* No error checking at all: it is as ugly as possible */ + while (value && i) { + tmp[--i] = hex[value % base]; + value /= base; + } + if (i == 16) + tmp[--i] = '0'; + ret = 16 - i; + while (i < 16) + *(out++) = tmp[i++]; + return ret; +} + +int pp_vsprintf(char *buf, const char *fmt, va_list args) +{ + char *s, *str = buf; + int base; + + for (; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + repeat: + fmt++; /* Skip '%' initially, other stuff later */ + base = 10; + /* Skip the complete format string */ + switch(*fmt) { + case '\0': + goto ret; + case '*': + /* should be precision, just eat it */ + base = va_arg(args, int); + /* fall through: discard unknown stuff */ + default: + goto repeat; + + /* Special cases for conversions */ + + case 'c': /* char: supported */ + *str++ = (unsigned char) va_arg(args, int); + break; + case 's': /* string: supported */ + s = va_arg(args, char *); + while (*s) + *str++ = *s++; + break; + case 'n': /* number-thus-far: not supported */ + break; + case '%': /* supported */ + *str++ = '%'; + break; + + /* integers are more or less printed */ + case 'p': + case 'x': + case 'X': + base = 16; + case 'o': + if (base == 10) /* yet unchaged */ + base = 8; + case 'd': + case 'i': + case 'u': + str += number(str, va_arg(args, int), base); + break; + } + } + ret: + *str = '\0'; + return str - buf; + + +}