Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
6e577f1906 | |||
925ba68c3c | |||
|
1577a74d58 | ||
|
ecd9879655 | ||
|
fa8e81e288 | ||
ef68f9c378 | |||
4618e66f55 | |||
0e157084ea | |||
6b227ba908 | |||
7f18ff6773 | |||
36c5d3f68a | |||
e4f517c020 | |||
0f9a68c578 | |||
1c90bf55b1 | |||
36af47eab8 | |||
cf740c34c3 | |||
51588e455b | |||
b7b16197f9 | |||
efd1d76428 | |||
cc842efe0b | |||
2c0eb3aff1 |
21
.github/workflows/c-cpp.yml
vendored
Normal file
21
.github/workflows/c-cpp.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: prep
|
||||
run: make prep
|
||||
- name: make
|
||||
run: make
|
||||
- name: test
|
||||
run: ./build/lat -V
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -130,4 +130,3 @@ $RECYCLE.BIN/
|
||||
*.lnk
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/c,macos,windows,linux,c
|
||||
|
||||
|
23
LICENSE
Normal file
23
LICENSE
Normal file
@ -0,0 +1,23 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
8
Makefile
8
Makefile
@ -6,7 +6,11 @@ ODIR:=obj
|
||||
BINDIR:=build
|
||||
|
||||
CC:=cc
|
||||
CFLAGS:=-I$(IDIR) -Wall -Wextra -pedantic -Ofast
|
||||
# OMG SO FAST (see https://www.shlomifish.org/humour/by-others/funroll-loops/Gentoo-is-Rice.html)
|
||||
# CFLAGS:=-I$(IDIR) -Wall -Wextra -pedantic -Ofast -faggressive-loop-optimizations -funroll-all-loops -march=native
|
||||
# For a stable experience
|
||||
CFLAGS:=-I$(IDIR) -Wall -Wextra -pedantic -O2 -march=native
|
||||
|
||||
LIB:=
|
||||
|
||||
DEPS:=$($(IDIR)/%.h)
|
||||
@ -22,7 +26,6 @@ $(ODIR)/%.o: %.c $(DEPS)
|
||||
$(CC) -c -o $@ $< $(CFLAGS) $(LIB)
|
||||
|
||||
$(NAME): $(OBJ)
|
||||
@echo "--don't forget to set $(NAME)'s version--"
|
||||
$(CC) -o $(BINDIR)/$@ $^ $(CFLAGS) $(LIB)
|
||||
|
||||
.PHONY: prep
|
||||
@ -31,7 +34,6 @@ prep:
|
||||
-@mkdir -p $(IDIR)
|
||||
-@mkdir -p $(ODIR)
|
||||
-@mkdir -p $(BINDIR)
|
||||
@echo $(BINDIR)/ >> .gitignore
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
|
47
README.md
Normal file
47
README.md
Normal file
@ -0,0 +1,47 @@
|
||||
# lat
|
||||
> lat | lazy cat - a cat clone with some quality-of-life embellishments
|
||||
|
||||
## About
|
||||
|
||||
`lat` is a solution to a problem that doesn't exist. It's the awkward middle child in-between `cat` and `bat`. It was created because the author didn't want to have to configure `bat` just to get decent file printing, but wanted a little more control than `cat` offered.
|
||||
|
||||
`lat` does not expect to be used. `lat` expects to be forgotten and shunted into a corner because it does not belong in the slightest.
|
||||
|
||||
## Install
|
||||
`lat` is not yet at a stable version (`v1.0.0`), so it is not on any package managers.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/secondary-smiles/lat.git
|
||||
|
||||
cd lat
|
||||
|
||||
make
|
||||
|
||||
./build/lat -V
|
||||
|
||||
# now add lat to your $PATH/do whatever you want with the binary
|
||||
```
|
||||
|
||||
## Helptext
|
||||
> `lat -h`
|
||||
|
||||
```text
|
||||
lat | lazy cat - a cat clone with some quality-of-life embellishments
|
||||
|
||||
usage: lat [-cltbrpneVh] [file...]
|
||||
|
||||
options:
|
||||
-c toggle color
|
||||
-l toggle line numbers
|
||||
-t toggle file info headers
|
||||
-b set binary mode, -b forces binary and -bb forces NOT binary
|
||||
-r print everything (headers, line numbers, etc.) to stdout (or equivalent)
|
||||
-p print file with the pager (uses less)
|
||||
-n <name> manually set the name of the file shown in the title
|
||||
-e <program> link extension to lat
|
||||
-V show program version
|
||||
-h display this help text
|
||||
|
||||
environment:
|
||||
NO_COLOR, see https://no-color.org/
|
||||
```
|
@ -2,10 +2,10 @@
|
||||
#define ARG_H
|
||||
#include <stdbool.h>
|
||||
|
||||
#define LAT_VERSION "0.11.1"
|
||||
#define LAT_VERSION "0.13.0"
|
||||
|
||||
struct config {
|
||||
bool stdin;
|
||||
bool isstdin;
|
||||
bool process;
|
||||
bool color;
|
||||
bool lines;
|
||||
@ -13,6 +13,8 @@ struct config {
|
||||
int force_binary;
|
||||
bool literal;
|
||||
bool pager;
|
||||
char *name;
|
||||
char *extension;
|
||||
bool has_read_stdin;
|
||||
};
|
||||
|
||||
|
54
social/binary.tape
Normal file
54
social/binary.tape
Normal file
@ -0,0 +1,54 @@
|
||||
Require lat
|
||||
Output social/render/binary.gif
|
||||
|
||||
Set Theme "Gruvbox Dark"
|
||||
Set WindowBar Rings
|
||||
Set BorderRadius 10
|
||||
Set Margin 10
|
||||
|
||||
Set FontSize 32
|
||||
Set Width 2400
|
||||
Set Height 1200
|
||||
Set TypingSpeed 0.2
|
||||
|
||||
Type "lat src/main.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 5s
|
||||
|
||||
Type "clear"
|
||||
Sleep 1s
|
||||
Enter
|
||||
|
||||
Sleep 2s
|
||||
|
||||
Type "lat -b src/main.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 5s
|
||||
|
||||
Type "clear"
|
||||
Sleep 1s
|
||||
Enter
|
||||
|
||||
Sleep 2s
|
||||
|
||||
Type "lat ./build/lat"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 5s
|
||||
|
||||
Type "clear"
|
||||
Sleep 1s
|
||||
Enter
|
||||
|
||||
Sleep 2s
|
||||
|
||||
Type "lat -bb ./build/lat"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 5s
|
31
social/color.tape
Normal file
31
social/color.tape
Normal file
@ -0,0 +1,31 @@
|
||||
Require lat
|
||||
Output social/render/color.gif
|
||||
|
||||
Set Theme "Gruvbox Dark"
|
||||
Set WindowBar Rings
|
||||
Set BorderRadius 10
|
||||
Set Margin 10
|
||||
|
||||
Set FontSize 32
|
||||
Set Width 2400
|
||||
Set Height 1200
|
||||
Set TypingSpeed 0.2
|
||||
|
||||
Type "lat src/main.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 5s
|
||||
|
||||
Type "clear"
|
||||
Sleep 1s
|
||||
Enter
|
||||
|
||||
Sleep 2s
|
||||
|
||||
Type "lat -c src/main.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 5s
|
||||
|
41
social/fzf_embed.tape
Normal file
41
social/fzf_embed.tape
Normal file
@ -0,0 +1,41 @@
|
||||
Require lat
|
||||
Output social/render/fzf_embed.gif
|
||||
|
||||
Set Theme "Gruvbox Dark"
|
||||
Set WindowBar Rings
|
||||
Set BorderRadius 10
|
||||
Set Margin 10
|
||||
|
||||
Set FontSize 32
|
||||
Set Width 2400
|
||||
Set Height 1200
|
||||
Set TypingSpeed 0.2
|
||||
|
||||
Type "fzf --preview 'lat -r {}'"
|
||||
Sleep 1s
|
||||
|
||||
Enter
|
||||
Sleep 2s
|
||||
|
||||
Type "main.c"
|
||||
Sleep 2s
|
||||
Backspace 7
|
||||
Sleep 1s
|
||||
|
||||
Type "types.h"
|
||||
Sleep 1s
|
||||
Backspace 8
|
||||
Sleep 2s
|
||||
|
||||
Type "file.c"
|
||||
Sleep 3s
|
||||
Backspace 7
|
||||
Sleep 2s
|
||||
|
||||
Up@3s 15
|
||||
|
||||
Sleep 3s
|
||||
|
||||
Enter
|
||||
|
||||
Sleep 2s
|
32
social/headers.tape
Normal file
32
social/headers.tape
Normal file
@ -0,0 +1,32 @@
|
||||
Require lat
|
||||
Output social/render/headers.gif
|
||||
|
||||
Set Theme "Gruvbox Dark"
|
||||
Set WindowBar Rings
|
||||
Set BorderRadius 10
|
||||
Set Margin 10
|
||||
|
||||
Set FontSize 32
|
||||
Set Width 2400
|
||||
Set Height 1200
|
||||
Set TypingSpeed 0.2
|
||||
|
||||
Type "lat src/main.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 5s
|
||||
|
||||
Type "clear"
|
||||
Sleep 1s
|
||||
Enter
|
||||
|
||||
Sleep 2s
|
||||
|
||||
Type "lat -t src/main.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 5s
|
||||
|
||||
|
24
social/lat_demo.tape
Normal file
24
social/lat_demo.tape
Normal file
@ -0,0 +1,24 @@
|
||||
Require lat
|
||||
Output social/render/lat_demo.gif
|
||||
|
||||
Set Theme "Gruvbox Dark"
|
||||
Set WindowBar Rings
|
||||
Set BorderRadius 10
|
||||
Set Margin 10
|
||||
|
||||
Set FontSize 32
|
||||
Set Width 2400
|
||||
Set Height 2000
|
||||
Set TypingSpeed 0.2
|
||||
|
||||
Type "lat Makefile"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 4s
|
||||
|
||||
Type "lat -h"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 4s
|
30
social/line_numbers.tape
Normal file
30
social/line_numbers.tape
Normal file
@ -0,0 +1,30 @@
|
||||
Require lat
|
||||
Output social/render/line_numbers.gif
|
||||
|
||||
Set Theme "Gruvbox Dark"
|
||||
Set WindowBar Rings
|
||||
Set BorderRadius 10
|
||||
Set Margin 10
|
||||
|
||||
Set FontSize 32
|
||||
Set Width 2400
|
||||
Set Height 1200
|
||||
Set TypingSpeed 0.2
|
||||
|
||||
Type "lat src/main.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 4s
|
||||
|
||||
Type "clear"
|
||||
Sleep 1s
|
||||
Enter
|
||||
|
||||
Sleep 2s
|
||||
|
||||
Type "lat -n src/main.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 4s
|
46
social/literal.tape
Normal file
46
social/literal.tape
Normal file
@ -0,0 +1,46 @@
|
||||
Require lat
|
||||
Output social/render/literal.gif
|
||||
|
||||
Set Theme "Gruvbox Dark"
|
||||
Set WindowBar Rings
|
||||
Set BorderRadius 10
|
||||
Set Margin 10
|
||||
|
||||
Set FontSize 32
|
||||
Set Width 2400
|
||||
Set Height 1200
|
||||
Set TypingSpeed 0.2
|
||||
|
||||
Type "lat src/main.c > example.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 5s
|
||||
|
||||
Type "cat example.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 5s
|
||||
|
||||
Type "clear"
|
||||
Sleep 1s
|
||||
Enter
|
||||
|
||||
Sleep 2s
|
||||
|
||||
Type "lat -r src/main.c > example.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 3s
|
||||
|
||||
Type "cat example.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 5s
|
||||
|
||||
Hide
|
||||
Type "rm example.c"
|
||||
Enter
|
37
social/name.tape
Normal file
37
social/name.tape
Normal file
@ -0,0 +1,37 @@
|
||||
Require lat
|
||||
Output social/render/name.gif
|
||||
|
||||
Set Theme "Gruvbox Dark"
|
||||
Set WindowBar Rings
|
||||
Set BorderRadius 10
|
||||
Set Margin 10
|
||||
|
||||
Set FontSize 32
|
||||
Set Width 2400
|
||||
Set Height 1200
|
||||
Set TypingSpeed 0.2
|
||||
|
||||
Type "lat"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Type "hello, world!"
|
||||
Enter
|
||||
Sleep 3s
|
||||
|
||||
Ctrl+d
|
||||
|
||||
Sleep 3s
|
||||
|
||||
Type "lat -n "custom name" src/main.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Type "hello, world!"
|
||||
Enter
|
||||
Sleep 3s
|
||||
|
||||
Ctrl+d
|
||||
|
||||
Sleep 4s
|
||||
|
40
social/pager.tape
Normal file
40
social/pager.tape
Normal file
@ -0,0 +1,40 @@
|
||||
Require lat
|
||||
Output social/render/pager.gif
|
||||
|
||||
Set Theme "Gruvbox Dark"
|
||||
Set WindowBar Rings
|
||||
Set BorderRadius 10
|
||||
Set Margin 10
|
||||
|
||||
Set FontSize 32
|
||||
Set Width 2400
|
||||
Set Height 1200
|
||||
Set TypingSpeed 0.2
|
||||
|
||||
Type "lat src/main.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 5s
|
||||
|
||||
Type "clear"
|
||||
Sleep 1s
|
||||
Enter
|
||||
|
||||
Sleep 2s
|
||||
|
||||
Type "lat -p src/main.c"
|
||||
Sleep 2s
|
||||
Enter
|
||||
|
||||
Sleep 5s
|
||||
|
||||
Down 100
|
||||
|
||||
Sleep 3s
|
||||
|
||||
Type "q"
|
||||
Sleep 4s
|
||||
|
||||
|
||||
|
168
src/lib/arg.c
168
src/lib/arg.c
@ -1,11 +1,16 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdnoreturn.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "arg.h"
|
||||
#include "util.h"
|
||||
|
||||
#define LAT_USAGE "usage: lat [-cntblpVh] [file...]"
|
||||
#define LAT_SHORT_ARGS "cltbrpn:e:Vh"
|
||||
#define LAT_USAGE "usage: lat [-cltbrpneVh] [file...]"
|
||||
|
||||
struct config conf;
|
||||
|
||||
void help(void) {
|
||||
printf("lat | lazy cat - a cat clone with some quality-of-life "
|
||||
@ -13,113 +18,41 @@ void help(void) {
|
||||
|
||||
printf("%s\n\n", LAT_USAGE);
|
||||
printf("options:\n"
|
||||
"\t-c, --color\t toggle color\n"
|
||||
"\t-n, --lines\t toggle line numbers\n"
|
||||
"\t-t, --headers\t toggle file info headers\n"
|
||||
"\t-b, --binary\t toggle binary mode, -b forces binary and -bb forces "
|
||||
"NOT binary\n"
|
||||
"\t-l, --literal\t print everything to stdout (or equivalent)\n"
|
||||
"\t-p, --pager\t print file with the pager (uses less)\n"
|
||||
"\t-V, --version\t show program version\n"
|
||||
"\t-h, --help\t display this help text (--help shows additional "
|
||||
"info)\n\n");
|
||||
"\t-c toggle color\n"
|
||||
"\t-l toggle line numbers\n"
|
||||
"\t-t toggle file info headers\n"
|
||||
"\t-b set binary mode, -b forces binary and -bb forces NOT "
|
||||
"binary\n"
|
||||
"\t-r print everything (headers, line numbers, etc.) to "
|
||||
"stdout (or equivalent)\n"
|
||||
"\t-p disable or enable pager (uses less)\n"
|
||||
"\t-n <name> manually set the name of the file shown in the title\n"
|
||||
// "\t-e <program> NONFUNCTIONAL (will be added soon) link extension
|
||||
// to lat\n"
|
||||
"\t-V show program version\n"
|
||||
"\t-h display this help text\n\n");
|
||||
printf("environment:\n"
|
||||
"\tNO_COLOR, see https://no-color.org/\n\n");
|
||||
}
|
||||
|
||||
void examples(void) {
|
||||
printf(
|
||||
"examples:\n"
|
||||
"\tlat file1\n\t\t print the contents of file1 with the default "
|
||||
"formatting\n"
|
||||
"\tlat - file1\n\t\t read from stdin (the '-' flag reads from "
|
||||
"stdin) "
|
||||
"and then print the contents of stdin and file1\n"
|
||||
"\tlat -nc file1 file2\n\t\t print the contents of file1 and "
|
||||
"file2 "
|
||||
"without printing line numbers or colors\n"
|
||||
"\tlat --binary file.txt\n\t\t force file.txt to be treated as a binary "
|
||||
"file\n"
|
||||
"\tlat -bb --pager file.txt\n\t\t force file.txt to NOT be treated "
|
||||
"as a binary file and print it in the pager\n"
|
||||
"\tcurl example.com | lat\n\t\t pipe the results of 'curl example.com' "
|
||||
"into lat\n"
|
||||
"\tfzf --preview 'lat -l {}'\n\t\t use lat as the file viewer in fzf\n"
|
||||
);
|
||||
"\tNO_COLOR, see https://no-color.org/\n");
|
||||
}
|
||||
|
||||
void version(void) {
|
||||
printf("lat - v%s built %s at %s\n", LAT_VERSION, __DATE__, __TIME__);
|
||||
}
|
||||
|
||||
struct config conf;
|
||||
void argerr(char *r, char *arg) {
|
||||
printf("lat: %s '%s'\n\n", r, arg);
|
||||
|
||||
printf("%s\n", LAT_USAGE);
|
||||
printf("run '--help' for more information\n");
|
||||
noreturn void argerr(void) {
|
||||
printf("\n%s\n", LAT_USAGE);
|
||||
printf("run '-h' for more information\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void parselongarg(char *arg) {
|
||||
if (strcmp(arg, "--color") == 0) {
|
||||
conf.color = !conf.color;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(arg, "--lines") == 0) {
|
||||
conf.lines = !conf.lines;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(arg, "--headers") == 0) {
|
||||
conf.headers = !conf.headers;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(arg, "--binary") == 0) {
|
||||
if (conf.force_binary < 0)
|
||||
conf.force_binary = 1;
|
||||
else
|
||||
conf.force_binary = !conf.force_binary;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(arg, "--literal") == 0) {
|
||||
conf.literal = !conf.literal;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(arg, "--pager") == 0) {
|
||||
conf.pager = !conf.pager;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(arg, "--help") == 0) {
|
||||
help();
|
||||
examples();
|
||||
exit(EXIT_SUCCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(arg, "--version") == 0) {
|
||||
version();
|
||||
exit(EXIT_SUCCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
argerr("unrecognized arg", arg);
|
||||
}
|
||||
|
||||
void parseshortarg(char *arg) {
|
||||
size_t i = 1;
|
||||
while (arg[i] != '\0') {
|
||||
char c = arg[i];
|
||||
switch (c) {
|
||||
int parseargs(int argc, char *argv[]) {
|
||||
char opt;
|
||||
while ((opt = getopt(argc, argv, LAT_SHORT_ARGS)) != -1) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
conf.color = !conf.color;
|
||||
break;
|
||||
case 'n':
|
||||
case 'l':
|
||||
conf.lines = !conf.lines;
|
||||
break;
|
||||
case 't':
|
||||
@ -131,12 +64,18 @@ void parseshortarg(char *arg) {
|
||||
else
|
||||
conf.force_binary = !conf.force_binary;
|
||||
break;
|
||||
case 'l':
|
||||
case 'r':
|
||||
conf.literal = !conf.literal;
|
||||
break;
|
||||
case 'p':
|
||||
conf.pager = !conf.pager;
|
||||
break;
|
||||
case 'n':
|
||||
conf.name = optarg;
|
||||
break;
|
||||
case 'e':
|
||||
conf.extension = optarg;
|
||||
break;
|
||||
case 'V':
|
||||
version();
|
||||
exit(EXIT_SUCCESS);
|
||||
@ -145,39 +84,10 @@ void parseshortarg(char *arg) {
|
||||
help();
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
default: {
|
||||
char *str = malloc(2);
|
||||
str[0] = c;
|
||||
str[1] = '\0';
|
||||
argerr("unrecognized flag", str);
|
||||
free(str);
|
||||
default:
|
||||
argerr();
|
||||
break;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
int parseargs(int argc, char *argv[]) {
|
||||
int i;
|
||||
for (i = 1; i < argc; i++) { // offset for argv[0]
|
||||
char *arg = argv[i];
|
||||
|
||||
if (arg[0] == '-' && arg[1] == '\0') {
|
||||
return i;
|
||||
}
|
||||
|
||||
if (arg[0] == '-') {
|
||||
if (arg[1] == '-') {
|
||||
parselongarg(arg);
|
||||
continue;
|
||||
}
|
||||
|
||||
parseshortarg(arg);
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
return optind;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "types.h"
|
||||
#include "util.h"
|
||||
#include "arg.h"
|
||||
|
||||
bool isbinary(struct filedata *f) {
|
||||
|
||||
@ -22,7 +23,7 @@ bool isbinary(struct filedata *f) {
|
||||
}
|
||||
}
|
||||
|
||||
struct filedata readfile(FILE *fp, bool isstdin) {
|
||||
struct filedata readfile(FILE *fp) {
|
||||
struct filedata f;
|
||||
|
||||
f.lc = 0;
|
||||
@ -32,7 +33,7 @@ struct filedata readfile(FILE *fp, bool isstdin) {
|
||||
f.buf = NULL;
|
||||
f.lines = NULL;
|
||||
|
||||
if (isstdin) {
|
||||
if (conf.isstdin) {
|
||||
size_t bufsize = 1024;
|
||||
f.buf = malloc(bufsize);
|
||||
if (f.buf == NULL)
|
||||
@ -42,7 +43,6 @@ struct filedata readfile(FILE *fp, bool isstdin) {
|
||||
while (fread(&c, 1, 1, fp) > 0) {
|
||||
if (f.buflen == bufsize - 1) {
|
||||
bufsize *= 2;
|
||||
|
||||
char *new_buf = realloc(f.buf, bufsize);
|
||||
if (new_buf == NULL)
|
||||
die("realloc");
|
||||
|
@ -1,12 +1,15 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "util.h"
|
||||
|
||||
void appendline(struct filedata *f, char *data, size_t len) {
|
||||
f->lines = realloc(f->lines, sizeof(struct line) * (f->lc + 1));
|
||||
if (f->lines == NULL)
|
||||
die("realloc");
|
||||
|
||||
size_t loc = f->lc;
|
||||
|
||||
@ -20,7 +23,7 @@ void loadlines(struct filedata *f) {
|
||||
f->lc = 0;
|
||||
|
||||
size_t offset = 0;
|
||||
size_t linelen = 4096;
|
||||
size_t linelen = 1024;
|
||||
char *line = malloc(linelen);
|
||||
if (line == NULL)
|
||||
die("malloc");
|
||||
@ -28,10 +31,11 @@ void loadlines(struct filedata *f) {
|
||||
for (size_t i = 0; i < f->buflen; i++) {
|
||||
char c = f->buf[i];
|
||||
if (c == '\n') {
|
||||
if (offset < linelen) { // shrink
|
||||
if (offset >= 1 && offset < linelen) { // shrink to fit
|
||||
char *new_line = realloc(line, offset);
|
||||
if (new_line == NULL)
|
||||
die("realloc");
|
||||
|
||||
line = new_line;
|
||||
}
|
||||
|
||||
@ -59,7 +63,7 @@ void loadlines(struct filedata *f) {
|
||||
}
|
||||
|
||||
// capture last line
|
||||
if (offset < linelen) { // shrink
|
||||
if (offset >= 1 && offset < linelen) { // shrink
|
||||
char *new_line = realloc(line, offset);
|
||||
if (new_line == NULL)
|
||||
die("realloc");
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdnoreturn.h>
|
||||
|
||||
void die(const char *message) {
|
||||
noreturn void die(const char *message) {
|
||||
perror(message);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
115
src/main.c
115
src/main.c
@ -1,7 +1,6 @@
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "arg.h"
|
||||
@ -18,13 +17,60 @@
|
||||
FILE *st;
|
||||
FILE *err;
|
||||
|
||||
struct colors {
|
||||
char *invert_t;
|
||||
char *grey;
|
||||
char *reset;
|
||||
};
|
||||
|
||||
struct colors c;
|
||||
|
||||
void initcolor(void) {
|
||||
c.invert_t = conf.color ? INVERT_T : "";
|
||||
c.grey = conf.color ? GREY : "";
|
||||
c.reset = conf.color ? RESET : "";
|
||||
}
|
||||
|
||||
void printheadertop(char *filename, bool binary) {
|
||||
char *name = conf.name == NULL ? filename : conf.name;
|
||||
char *addon = binary ? "<binary>" : "";
|
||||
if (conf.isstdin && !conf.pager)
|
||||
fprintf(err, "\x1b[2K\r%s%s%s%s\n", c.invert_t, name, addon, c.reset);
|
||||
else
|
||||
fprintf(err, "%s%s%s%s\n", c.invert_t, name, addon, c.reset);
|
||||
}
|
||||
|
||||
void printheaderbottom(size_t buflen) {
|
||||
float rounded;
|
||||
char *format = formatbytes(buflen, &rounded);
|
||||
|
||||
fprintf(err, "%s%.2f %s%s\n", c.invert_t, rounded, format, c.reset);
|
||||
}
|
||||
|
||||
void run(FILE *fp, char *filename, bool tty) {
|
||||
const char *invert_t = conf.color ? INVERT_T : "";
|
||||
const char *grey = conf.color ? GREY : "";
|
||||
const char *reset = conf.color ? RESET : "";
|
||||
initcolor();
|
||||
|
||||
struct filedata f;
|
||||
f = readfile(fp, conf.stdin);
|
||||
f = readfile(fp, conf.isstdin);
|
||||
|
||||
// any/all processing to be done
|
||||
// TODO: maybe multithread?
|
||||
conf.process = (tty && !f.binary);
|
||||
if (conf.process) { // file display processing
|
||||
loadlines(&f);
|
||||
}
|
||||
|
||||
if (conf.extension != NULL) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
struct winsize w;
|
||||
|
||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1 || w.ws_col != 0) {
|
||||
if (w.ws_row <= f.lc + 5) {
|
||||
conf.pager = !conf.pager;
|
||||
}
|
||||
}
|
||||
|
||||
if (conf.pager) {
|
||||
st = popen("less", "w");
|
||||
@ -45,28 +91,21 @@ void run(FILE *fp, char *filename, bool tty) {
|
||||
}
|
||||
|
||||
if (conf.headers) {
|
||||
char *addon = f.binary ? "<binary>" : "";
|
||||
if (conf.stdin && !conf.pager)
|
||||
fprintf(err, "\x1b[2K\r%s%s%s%s\n", invert_t, basename(filename), addon,
|
||||
reset);
|
||||
else
|
||||
fprintf(err, "%s%s%s%s\n", invert_t, basename(filename), addon, reset);
|
||||
}
|
||||
|
||||
conf.process = (tty && !f.binary);
|
||||
if (conf.process) { // file display processing
|
||||
loadlines(&f);
|
||||
printheadertop(filename, f.binary);
|
||||
}
|
||||
|
||||
if (conf.process) {
|
||||
int linecount = 1;
|
||||
for (int i = 0; i < f.lc; i++) {
|
||||
if (conf.lines) {
|
||||
char *padding = linepad(linecount, f.lc);
|
||||
fprintf(st, "%s%s%d│%s ", grey, padding, i + 1, reset);
|
||||
{ // line numbers
|
||||
char *padding = linepad(linecount, f.lc);
|
||||
fprintf(err, "%s%s%d│%s ", c.grey, padding, i + 1, c.reset);
|
||||
free(padding);
|
||||
}
|
||||
|
||||
fwrite(f.lines[i].buf, 1, f.lines[i].len, st);
|
||||
fprintf(st, "\n");
|
||||
free(padding);
|
||||
linecount++;
|
||||
} else {
|
||||
fprintf(st, "%s\n", f.lines[i].buf);
|
||||
@ -76,18 +115,17 @@ void run(FILE *fp, char *filename, bool tty) {
|
||||
} else {
|
||||
fwrite(f.buf, 1, f.buflen, st);
|
||||
fflush(st);
|
||||
fwrite("\n", 1, 1, err);
|
||||
if (tty)
|
||||
fwrite("\n", 1, 1, err);
|
||||
}
|
||||
free(f.buf);
|
||||
free(f.lines);
|
||||
|
||||
fflush(st); // prevent timing inconsistencies between st and err
|
||||
fflush(err);
|
||||
|
||||
if (conf.headers) {
|
||||
float rounded;
|
||||
char *format = formatbytes(f.buflen, &rounded);
|
||||
|
||||
fprintf(err, "%s%.2f %s%s\n", invert_t, rounded, format, reset);
|
||||
printheaderbottom(f.buflen);
|
||||
}
|
||||
|
||||
if (conf.pager) {
|
||||
@ -97,14 +135,18 @@ void run(FILE *fp, char *filename, bool tty) {
|
||||
|
||||
void initconf(void) {
|
||||
conf.force_binary = -1;
|
||||
conf.stdin = false;
|
||||
conf.isstdin = false;
|
||||
conf.has_read_stdin = false;
|
||||
conf.pager = false;
|
||||
conf.literal = false;
|
||||
|
||||
conf.process = true;
|
||||
conf.headers = true;
|
||||
conf.color = true;
|
||||
conf.lines = true;
|
||||
|
||||
conf.name = NULL;
|
||||
conf.extension = NULL;
|
||||
}
|
||||
|
||||
void clearstdin(void) {
|
||||
@ -128,40 +170,45 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
bool tty = isatty(STDOUT_FILENO);
|
||||
|
||||
int offset = parseargs(argc, argv);
|
||||
|
||||
conf.headers = conf.headers && tty;
|
||||
|
||||
if (argc > 1) {
|
||||
int offset = parseargs(argc, argv);
|
||||
|
||||
tty = tty || conf.literal;
|
||||
conf.headers = conf.headers && tty; // tty still overrides user
|
||||
conf.pager = conf.pager && tty;
|
||||
|
||||
for (int i = offset; i < argc; i++) {
|
||||
if (*argv[i] == '-') {
|
||||
if (conf.has_read_stdin)
|
||||
clearstdin();
|
||||
conf.has_read_stdin = true;
|
||||
conf.stdin = true;
|
||||
conf.isstdin = true;
|
||||
run(stdin, "stdin", tty);
|
||||
if (tty && (i + 1 != argc)) {
|
||||
fprintf(err, "\n"); // separate concurrent files in tty
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
conf.stdin = false;
|
||||
conf.isstdin = false;
|
||||
FILE *fp = fopen(argv[i], "rb");
|
||||
if (fp == NULL)
|
||||
die(argv[i]);
|
||||
run(fp, argv[i], tty);
|
||||
fclose(fp);
|
||||
if (tty && (i + 1 != argc)) {
|
||||
printf("offset: %d argc: %d\n", i, argc);
|
||||
fprintf(err, "\n"); // separate concurrent files in tty
|
||||
}
|
||||
}
|
||||
|
||||
if (offset == argc) {
|
||||
conf.stdin = true;
|
||||
conf.isstdin = true;
|
||||
run(stdin, "stdin", tty);
|
||||
}
|
||||
} else {
|
||||
conf.stdin = true;
|
||||
conf.isstdin = true;
|
||||
run(stdin, "stdin", tty); // for piped-input or repl-like behavior
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user