Serenity Operating System
at portability 117 lines 4.5 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/String.h> 28#include <AK/Vector.h> 29#include <LibCore/ArgsParser.h> 30 31#include <stdio.h> 32#include <string.h> 33 34enum NumberStyle { 35 NumberAllLines, 36 NumberNonEmptyLines, 37 NumberNoLines, 38}; 39 40int main(int argc, char** argv) 41{ 42 NumberStyle number_style = NumberNonEmptyLines; 43 int increment = 1; 44 const char* separator = " "; 45 int start_number = 1; 46 int number_width = 6; 47 Vector<const char*> files; 48 49 Core::ArgsParser args_parser; 50 51 Core::ArgsParser::Option number_style_option { 52 true, 53 "Line numbering style: 't' for non-empty lines, 'a' for all lines, 'n' for no lines", 54 "body-numbering", 55 'b', 56 "style", 57 [&number_style](const char* s) { 58 if (!strcmp(s, "t")) 59 number_style = NumberNonEmptyLines; 60 else if (!strcmp(s, "a")) 61 number_style = NumberAllLines; 62 else if (!strcmp(s, "n")) 63 number_style = NumberNoLines; 64 else 65 return false; 66 67 return true; 68 } 69 }; 70 71 args_parser.add_option(move(number_style_option)); 72 args_parser.add_option(increment, "Line count increment", "increment", 'i', "number"); 73 args_parser.add_option(separator, "Separator between line numbers and lines", "separator", 's', "string"); 74 args_parser.add_option(start_number, "Initial line number", "startnum", 'v', "number"); 75 args_parser.add_option(number_width, "Number width", "width", 'w', "number"); 76 args_parser.add_positional_argument(files, "Files to process", "file", Core::ArgsParser::Required::No); 77 args_parser.parse(argc, argv); 78 79 Vector<FILE*> file_pointers; 80 if (!files.is_empty()) { 81 for (auto& file : files) { 82 FILE* file_pointer = fopen(file, "r"); 83 if (!file_pointer) { 84 fprintf(stderr, "unable to open %s\n", file); 85 continue; 86 } 87 file_pointers.append(file_pointer); 88 } 89 } else { 90 file_pointers.append(stdin); 91 } 92 93 for (auto& file_pointer : file_pointers) { 94 int line_number = start_number - increment; // so the line number can start at 1 when added below 95 int previous_character = 0; 96 int next_character = 0; 97 while ((next_character = fgetc(file_pointer)) != EOF) { 98 if (previous_character == 0 || previous_character == '\n') { 99 if (next_character == '\n' && number_style != NumberAllLines) { 100 // Skip printing line count on empty lines. 101 printf("\n"); 102 continue; 103 } 104 if (number_style != NumberNoLines) 105 printf("%*d%s", number_width, (line_number += increment), separator); 106 else 107 printf("%*s", number_width, ""); 108 } 109 putchar(next_character); 110 previous_character = next_character; 111 } 112 fclose(file_pointer); 113 if (previous_character != '\n') 114 printf("\n"); // for cases where files have no trailing newline 115 } 116 return 0; 117}