/*++ Copyright (c) 2014 Minoca Corp. All Rights Reserved Module Name: cecho.c Abstract: This module implements the color echo application. Author: Evan Green 1-May-2014 Environment: POSIX --*/ // // ------------------------------------------------------------------- Includes // #include #include "swlib.h" #include // // ---------------------------------------------------------------- Definitions // #define CECHO_USAGE \ "usage: cecho [-f ] [-b ] [-neE]\n" \ "The cecho utility echoes command line parameters in color. Options are:\n"\ " -f -- Print with the given foreground color.\n" \ " -b -- Print with the given background color.\n" \ " -n -- Do not print a newline at the end.\n" \ " -e -- Enable escape processing.\n" \ " -E -- Disable escape processing.\n" \ "Use the -- argument to disable argument processing of all subsequent \n" \ "parameters. The color type can be one of:\n" \ " d -- Default color\n" \ " k -- Black\n" \ " r -- Dark red\n" \ " g -- Dark green\n" \ " y -- Dark yellow\n" \ " b -- Dark blue\n" \ " m -- Dark magenta\n" \ " c -- Dark cyan\n" \ " a -- Dark gray\n" \ " D -- Bold default\n" \ " A -- gray\n" \ " R -- bright red\n" \ " G -- bright green\n" \ " Y -- bright yellow\n" \ " B -- bright blue\n" \ " M -- bright magenta\n" \ " C -- bright cyan\n" \ " W -- white\n" // // ------------------------------------------------------ Data Type Definitions // // // ----------------------------------------------- Internal Function Prototypes // CONSOLE_COLOR ColorEchoConvertToColor ( CHAR Character ); // // -------------------------------------------------------------------- Globals // // // ------------------------------------------------------------------ Functions // INT ColorEchoMain ( INT ArgumentCount, CHAR **Arguments ) /*++ Routine Description: This routine is the main entry point for the color echo program. Arguments: ArgumentCount - Supplies the number of command line arguments the program was invoked with. Arguments - Supplies a tokenized array of command line arguments. Return Value: 0 on success. Non-zero on failure. --*/ { PSTR Argument; ULONG ArgumentIndex; ULONG ArgumentLength; CONSOLE_COLOR BackgroundColor; CHAR Character; ULONG CharacterIndex; CHAR DigitCount; BOOL EscapeProcessing; CONSOLE_COLOR ForegroundColor; BOOL PrintTrailingNewline; CHAR Value; BOOL WasBackslash; EscapeProcessing = FALSE; PrintTrailingNewline = TRUE; BackgroundColor = ConsoleColorDefault; ForegroundColor = ConsoleColorDefault; // // Loop through processing arguments. // for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) { Argument = Arguments[ArgumentIndex]; if (Argument[0] != '-') { break; } if (strcmp(Argument, "--help") == 0) { printf(CECHO_USAGE); return 1; } while (TRUE) { Argument += 1; if (Argument[0] == '\0') { break; } else if (Argument[0] == 'e') { EscapeProcessing = TRUE; } else if (Argument[0] == 'E') { EscapeProcessing = FALSE; } else if (Argument[0] == 'n') { PrintTrailingNewline = FALSE; } else if (Argument[0] == 'f') { ForegroundColor = ColorEchoConvertToColor(Argument[1]); if (ForegroundColor == -1) { return 1; } Argument += 1; } else if (Argument[0] == 'b') { BackgroundColor = ColorEchoConvertToColor(Argument[1]); if (BackgroundColor == -1) { return 1; } Argument += 1; } else if (Argument[0] == '-') { break; } else { break; } } if (Argument[0] != '\0') { break; } } // // Echo out the remainder of the arguments. // while (ArgumentIndex < ArgumentCount) { Argument = Arguments[ArgumentIndex]; ArgumentIndex += 1; // // If not processing backslashes or there are none, just print it // directly and continue. // if ((EscapeProcessing == FALSE) || (strchr(Argument, '\\') == NULL)) { SwPrintInColor(BackgroundColor, ForegroundColor, "%s", Argument); // // Escape the darn thing by looping through every character in the // string. // } else { Value = 0; DigitCount = 0; WasBackslash = FALSE; ArgumentLength = strlen(Argument); for (CharacterIndex = 0; CharacterIndex < ArgumentLength; CharacterIndex += 1) { Character = Argument[CharacterIndex]; // // If a \0 was detected, then this is in the process of // working through \0NNN, where NNN is one to three octal // characters. // if (DigitCount != 0) { if ((Character >= '0') && (Character <= '7')) { Value = (Value * 8) + (Character - '0'); DigitCount += 1; if (DigitCount == 4) { DigitCount = 0; SwPrintInColor(BackgroundColor, ForegroundColor, "%c", Value); } // // This was a digit that counted towards the value, so // it shouldn't be considered for further printing. // continue; // // The number ended a bit early, so print it out and // consider this character for further printing. // } else { DigitCount = 0; SwPrintInColor(BackgroundColor, ForegroundColor, "%c", Value); } } if (WasBackslash != FALSE) { if (Character == 'a') { } else if (Character == 'b') { SwPrintInColor(BackgroundColor, ForegroundColor, "\b"); } else if (Character == 'c') { PrintTrailingNewline = FALSE; goto MainEnd; } else if (Character == 'f') { SwPrintInColor(BackgroundColor, ForegroundColor, "\f"); } else if (Character == 'n') { SwPrintInColor(BackgroundColor, ForegroundColor, "\n"); } else if (Character == 'r') { SwPrintInColor(BackgroundColor, ForegroundColor, "\r"); } else if (Character == 't') { SwPrintInColor(BackgroundColor, ForegroundColor, "\t"); } else if (Character == '\\') { SwPrintInColor(BackgroundColor, ForegroundColor, "\\"); } else if (Character == '0') { Value = 0; DigitCount = 1; } else { // // This backslash escape sequence isn't recognized, so // just print it out verbatim. // SwPrintInColor(BackgroundColor, ForegroundColor, "\\%c", Character); } // // Just a regular old character, print it out unless it begins // an escaped sequence. // } else if (Character != '\\') { SwPrintInColor(BackgroundColor, ForegroundColor, "%c", Character); } if (Character == '\\') { WasBackslash = !WasBackslash; } else { WasBackslash = FALSE; } } } if (ArgumentIndex != ArgumentCount) { SwPrintInColor(BackgroundColor, ForegroundColor, " "); } } MainEnd: if (PrintTrailingNewline != FALSE) { SwPrintInColor(BackgroundColor, ForegroundColor, "\n"); } return 0; } // // --------------------------------------------------------- Internal Functions // CONSOLE_COLOR ColorEchoConvertToColor ( CHAR Character ) /*++ Routine Description: This routine converts a color character to a console color enum. Arguments: Character - Supplies the character to convert. Return Value: Returns the console color on success. -1 if the character is not valid. --*/ { CONSOLE_COLOR Color; switch (Character) { case 'd': Color = ConsoleColorDefault; break; case 'k': Color = ConsoleColorBlack; break; case 'r': Color = ConsoleColorDarkRed; break; case 'g': Color = ConsoleColorDarkGreen; break; case 'y': Color = ConsoleColorDarkYellow; break; case 'b': Color = ConsoleColorDarkBlue; break; case 'm': Color = ConsoleColorDarkMagenta; break; case 'c': Color = ConsoleColorDarkCyan; break; case 'a': Color = ConsoleColorDarkGray; break; case 'D': Color = ConsoleColorBoldDefault; break; case 'A': Color = ConsoleColorGray; break; case 'R': Color = ConsoleColorRed; break; case 'G': Color = ConsoleColorGreen; break; case 'Y': Color = ConsoleColorYellow; break; case 'B': Color = ConsoleColorBlue; break; case 'M': Color = ConsoleColorMagenta; break; case 'C': Color = ConsoleColorCyan; break; case 'W': Color = ConsoleColorWhite; break; default: fprintf(stderr, "cecho: Invalid color '%c'.\n", Character); Color = -1; } return Color; }