/******************************************************************************* Copyright(C) Jonas 'Sortie' Termansen 2012. 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 3 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, see . column.cpp Columnate lists. *******************************************************************************/ #define _SORTIX_SOURCE #include #include #include #include #include #include #include #include #include #if !defined(VERSIONSTR) #define VERSIONSTR "unknown version" #endif int termwidth = 80; size_t linesused = 0; size_t lineslength = 0; char** lines = 0; size_t longestline = 0; size_t measurelength(const char* line) { size_t len = 0; bool escaped = false; while ( char c = *line++ ) { if ( escaped ) { if ( isalpha(c) ) escaped = false; continue; } if ( c == '\e' ) { escaped = true; continue; } len++; } return len; } bool processline(char* line) { if ( linesused == lineslength ) { size_t newlineslength = lineslength ? 2 * lineslength : 32; char** newlines = new char*[newlineslength]; memcpy(newlines, lines, sizeof(char*) * linesused); delete[] lines; lines = newlines; lineslength = newlineslength; } lines[linesused++] = line; size_t linelen = measurelength(line); if ( longestline < linelen ) { longestline = linelen; } return true; } bool processfp(const char* inputname, FILE* fp) { if ( strcmp(inputname, "-") == 0 ) { inputname = ""; } while ( true ) { size_t linesize; char* line = NULL; ssize_t linelen = getline(&line, &linesize, fp); if ( linelen < 0 ) { if ( feof(fp) ) { return true; } error(0, errno, "error reading: %s (%i)", inputname, fileno(fp)); return false; } line[--linelen] = 0; if ( !processline(line) ) { exit(1); } } } bool doformat() { size_t width = termwidth; size_t columnwidth = longestline + 2; size_t columns = width / columnwidth; if ( !columns ) { columns = 1; } bool newline = false; for ( size_t i = 0; i < linesused; i++ ) { newline = false; size_t column = i % columns; size_t offset = column * columnwidth; printf("\e[%zuG%s", offset+1, lines[i]); if ( columns <= column + 1 ) { printf("\n"); newline = true; } } if ( linesused && !newline ) { printf("\n"); } return true; } void usage(const char* argv0) { printf("usage: %s [--help | --version | --usage] [-c width] [ ...]\n", argv0); } void help(const char* argv0) { usage(argv0); } void version(const char* argv0) { FILE* fp = stdout; fprintf(fp, "%s (Sortix) %s\n", argv0, VERSIONSTR); fprintf(fp, "License GPLv3+: GNU GPL version 3 or later .\n"); fprintf(fp, "This is free software: you are free to change and redistribute it.\n"); fprintf(fp, "There is NO WARRANTY, to the extent permitted by law.\n"); } int main(int argc, char* argv[]) { struct winsize ws; if ( tcgetwinsize(1, &ws) == 0 ) termwidth = ws.ws_col; const char* argv0 = argv[0]; for ( int i = 1; i < argc; i++ ) { const char* arg = argv[i]; if ( arg[0] != '-' ) { continue; } if ( strcmp(arg, "-") == 0 ) { continue; } argv[i] = NULL; if ( strcmp(arg, "--") == 0 ) { break; } if ( strcmp(arg, "--usage") == 0 ) { usage(argv0); exit(0); } if ( strcmp(arg, "--help") == 0 ) { help(argv0); exit(0); } if ( strcmp(arg, "--version") == 0 ) { version(argv0); exit(0); } if ( strcmp(arg, "-c") == 0 ) { if ( i+1 == argc ) { usage(argv0); exit(1); } termwidth = atoi(argv[++i]); argv[i] = NULL; continue; } error(0, 0, "unknown option %s", arg); usage(argv0); return 1; } bool hadany = false; for ( int i = 1; i < argc; i++ ) { const char* arg = argv[i]; if ( !arg ) { continue; } bool isstdin = strcmp(arg, "-") == 0; FILE* fp = isstdin ? stdin : fopen(arg, "r"); if ( !fp ) { error(1, errno, "fopen failed: %s", arg); } hadany = true; if ( !processfp(arg, fp) ) { return 1; } if ( fp != stdin ) { fclose(fp); } } if ( !hadany ) { if ( !processfp("-", stdin) ) { return 1; } } if ( !doformat() ) { exit(1); } return 0; }