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;
+
+
+}