123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591 |
- /*++
- Copyright (c) 2013 Minoca Corp. All Rights Reserved
- Module Name:
- printf.c
- Abstract:
- This module implements the printf utility.
- Author:
- Evan Green 16-Jul-2013
- Environment:
- POSIX
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/lib/types.h>
- #include <ctype.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <string.h>
- #include "swlib.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- BOOL
- PrintfUnescapeString (
- PSTR String
- );
- VOID
- PrintfRemoveCarriageReturns (
- PSTR String
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- INT
- PrintfMain (
- INT ArgumentCount,
- CHAR **Arguments
- )
- /*++
- Routine Description:
- This routine implements the main entry point for the printf utility.
- Arguments:
- ArgumentCount - Supplies the number of arguments on the command line.
- Arguments - Supplies an array of pointers to strings representing the
- arguments.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PSTR AfterScan;
- PSTR Argument;
- ULONG ArgumentIndex;
- LONGLONG BigInteger;
- CHAR Character;
- CHAR ClobberedCharacter;
- ULONG ConversionIndex;
- CHAR ConversionSpecifier;
- CHAR Digit;
- ULONG DigitIndex;
- PSTR Format;
- BOOL FoundFormatSpecifiers;
- ULONG Index;
- INT Integer;
- BOOL PrintCharacter;
- BOOL QuadWord;
- INT ReturnValue;
- BOOL Stop;
- BOOL WasBackslash;
- if (ArgumentCount < 2) {
- ReturnValue = 1;
- goto MainEnd;
- }
- ReturnValue = 0;
- Format = Arguments[1];
- FoundFormatSpecifiers = FALSE;
- PrintfRemoveCarriageReturns(Format);
- ArgumentIndex = 2;
- Index = 0;
- Stop = FALSE;
- WasBackslash = FALSE;
- while (Stop == FALSE) {
- PrintCharacter = TRUE;
- Character = Format[Index];
- if (Character == '\0') {
- if ((ArgumentIndex < ArgumentCount) &&
- (FoundFormatSpecifiers != FALSE)) {
- Index = 0;
- WasBackslash = FALSE;
- continue;
- }
- break;
- }
- if (WasBackslash != FALSE) {
- if (Character == '\\') {
- Character = '\\';
- } else if (Character == 'a') {
- Character = '\a';
- } else if (Character == 'b') {
- Character = '\b';
- } else if (Character == 'f') {
- Character = '\f';
- } else if (Character == 'n') {
- Character = '\n';
- } else if (Character == 'r') {
- Character = '\r';
- } else if (Character == 't') {
- Character = '\t';
- } else if (Character == 'v') {
- Character = '\v';
- } else if (Character == 'x') {
- Character = 0;
- for (DigitIndex = 1; DigitIndex < 3; DigitIndex += 1) {
- Digit = Format[Index + DigitIndex];
- if (isdigit(Digit)) {
- Digit -= '0';
- } else if ((Digit >= 'A') && (Digit <= 'F')) {
- Digit = (Digit - 'A') + 0xA;
- } else if ((Digit >= 'a') && (Digit <= 'f')) {
- Digit = (Digit - 'a') + 0xA;
- } else {
- break;
- }
- Character = (Character * 16) + Digit;
- }
- Index += DigitIndex - 1;
- } else if ((Character >= '0') && (Character <= '7')) {
- //
- // The first digit is already in the character, which is why
- // the loop only iterates twice for three digits.
- //
- Character -= '0';
- for (DigitIndex = 1; DigitIndex < 3; DigitIndex += 1) {
- Digit = Format[Index + DigitIndex];
- if ((Digit < '0') || (Digit > '7')) {
- break;
- }
- Character = (Character * 8) + (Digit - '0');
- }
- Index += DigitIndex - 1;
- //
- // An unknown backslash escape was used. Treat the backslash
- // literally.
- //
- } else {
- printf("\\%c", Character);
- PrintCharacter = FALSE;
- }
- //
- // This character is not preceded by a backslash.
- //
- } else {
- if (Character == '\\') {
- PrintCharacter = FALSE;
- } else if (Character == '%') {
- ConversionIndex = Index + 1;
- //
- // Get through any flags.
- //
- while (TRUE) {
- Character = Format[ConversionIndex];
- if ((Character != '+') && (Character != '-') &&
- (Character != ' ') && (Character != '#') &&
- (Character != '0')) {
- break;
- }
- ConversionIndex += 1;
- }
- //
- // Get through any field width digits.
- //
- while (isdigit(Format[ConversionIndex])) {
- ConversionIndex += 1;
- }
- //
- // Get through an optional dot and precision.
- //
- if (Format[ConversionIndex] == '.') {
- ConversionIndex += 1;
- }
- while (isdigit(Format[ConversionIndex])) {
- ConversionIndex += 1;
- }
- //
- // Look to see if length modifiers exist that make this a quad
- // word. Then get past all length modifiers.
- //
- QuadWord = FALSE;
- if ((Format[ConversionIndex] == 'l') &&
- (Format[ConversionIndex + 1] == 'l')) {
- QuadWord = TRUE;
- }
- while (TRUE) {
- Character = Format[ConversionIndex];
- if ((Character != 'h') && (Character != 'l') &&
- (Character != 'j') && (Character != 'z') &&
- (Character != 't') && (Character != 'L')) {
- break;
- }
- ConversionIndex += 1;
- }
- //
- // Get the conversion specifier and temporarily null terminate
- // the format specifier.
- //
- ConversionSpecifier = Format[ConversionIndex];
- ConversionIndex += 1;
- ClobberedCharacter = Format[ConversionIndex];
- Format[ConversionIndex] = '\0';
- if (ArgumentIndex < ArgumentCount) {
- Argument = Arguments[ArgumentIndex];
- } else {
- Argument = NULL;
- }
- //
- // Convert an integer of some kind.
- //
- if ((ConversionSpecifier == 'd') ||
- (ConversionSpecifier == 'i') ||
- (ConversionSpecifier == 'o') ||
- (ConversionSpecifier == 'u') ||
- (ConversionSpecifier == 'x') ||
- (ConversionSpecifier == 'X') ||
- (ConversionSpecifier == 'c') ||
- (ConversionSpecifier == 'p') ||
- (ConversionSpecifier == 'C')) {
- if (QuadWord != FALSE) {
- BigInteger = strtoll(Argument, &AfterScan, 0);
- if (((BigInteger == -1) && (errno != 0)) ||
- (AfterScan == Argument)) {
- SwPrintError(0, Argument, "Invalid number");
- ReturnValue = errno;
- }
- printf(Format + Index, BigInteger);
- } else {
- if ((ConversionSpecifier == 'c') ||
- (ConversionSpecifier == 'C')) {
- Integer = 0;
- if (Argument != NULL) {
- Integer = Argument[0];
- }
- } else {
- Integer = strtol(Argument, &AfterScan, 0);
- if ((AfterScan == Argument) ||
- (*AfterScan != '\0')) {
- SwPrintError(0, Argument, "Invalid number");
- ReturnValue = errno;
- }
- }
- printf(Format + Index, Integer);
- }
- //
- // Convert a string.
- //
- } else if ((ConversionSpecifier == 's') ||
- (ConversionSpecifier == 'b')) {
- if ((ConversionSpecifier == 'b') && (Argument != NULL)) {
- Stop = PrintfUnescapeString(Argument);
- Format[ConversionIndex - 1] = 's';
- }
- if (Argument == NULL) {
- Argument = "";
- }
- PrintfRemoveCarriageReturns(Argument);
- printf(Format + Index, Argument);
- //
- // Oh, it's just an unescaped percent.
- //
- } else if (ConversionSpecifier == '%') {
- fputc('%', stdout);
- Argument = NULL;
- //
- // This is an unknown conversion specifier.
- //
- } else {
- SwPrintError(0,
- NULL,
- "Unknown conversion specifier '%c'",
- ConversionSpecifier);
- ReturnValue = 1;
- Argument = NULL;
- }
- if (Argument != NULL) {
- ArgumentIndex += 1;
- FoundFormatSpecifiers = TRUE;
- }
- //
- // Restore the string and move beyond this specifier.
- //
- Format[ConversionIndex] = ClobberedCharacter;
- Index = ConversionIndex - 1;
- PrintCharacter = FALSE;
- }
- }
- if (PrintCharacter != FALSE) {
- fputc(Character, stdout);
- }
- if (Character == '\\') {
- WasBackslash = !WasBackslash;
- } else {
- WasBackslash = FALSE;
- }
- Index += 1;
- }
- MainEnd:
- return ReturnValue;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- BOOL
- PrintfUnescapeString (
- PSTR String
- )
- /*++
- Routine Description:
- This routine unescapes backslash sequences \\ \a \b \f \n \r \t \v, \c, and
- \0ddd (where d is zero to three octal digits).
- Arguments:
- String - Supplies a pointer to the string to unescape.
- Return Value:
- TRUE if a \c was found.
- FALSE if no \c was found.
- --*/
- {
- CHAR Character;
- ULONG DeleteCount;
- CHAR Digit;
- ULONG DigitIndex;
- ULONG Index;
- BOOL Stop;
- UINTN StringSize;
- BOOL WasBackslash;
- Index = 0;
- StringSize = strlen(String) + 1;
- Stop = FALSE;
- WasBackslash = FALSE;
- while (Stop == FALSE) {
- Character = String[Index];
- if (Character == '\0') {
- break;
- }
- if (WasBackslash != FALSE) {
- DeleteCount = 1;
- if (Character == '\\') {
- Character = '\\';
- } else if (Character == 'a') {
- Character = '\a';
- } else if (Character == 'b') {
- Character = '\b';
- } else if (Character == 'c') {
- Character = '\0';
- Stop = TRUE;
- } else if (Character == 'f') {
- Character = '\f';
- } else if (Character == 'n') {
- Character = '\n';
- } else if (Character == 'r') {
- Character = '\r';
- } else if (Character == 't') {
- Character = '\t';
- } else if (Character == 'v') {
- Character = '\v';
- } else if (Character == '0') {
- Character = 0;
- for (DigitIndex = 1; DigitIndex < 4; DigitIndex += 1) {
- Digit = String[Index + DigitIndex];
- if ((Digit < '0') || (Digit > '7')) {
- break;
- }
- Character = (Character * 8) + (Digit - '0');
- }
- DeleteCount = 1 + DigitIndex;
- //
- // An unknown backslash escape was used. Treat the backslash
- // literally.
- //
- } else {
- DeleteCount = 0;
- }
- if (DeleteCount != 0) {
- Index -= 1;
- SwStringRemoveRegion(String,
- &StringSize,
- Index,
- DeleteCount);
- String[Index] = Character;
- }
- }
- if (Character == '\\') {
- WasBackslash = !WasBackslash;
- } else {
- WasBackslash = FALSE;
- }
- Index += 1;
- }
- return Stop;
- }
- VOID
- PrintfRemoveCarriageReturns (
- PSTR String
- )
- /*++
- Routine Description:
- This routine removes any \r characters from the input string, as they
- pile up in Windows platforms and are generally useless.
- Arguments:
- String - Supplies a pointer to the string to strip of \r characters.
- Return Value:
- None.
- --*/
- {
- UINTN Index;
- UINTN StringSize;
- StringSize = strlen(String) + 1;
- Index = 0;
- while (String[Index] != '\0') {
- if (String[Index] == '\r') {
- SwStringRemoveRegion(String, &StringSize, Index, 1);
- } else {
- Index += 1;
- }
- }
- return;
- }
|