Rename line to lines

* It can now extract multiple lines, I'm not super excited about the
  code, but it works at least
* Add ADVANCE_PTR macro to util
This commit is contained in:
Dylan Lom 2021-02-22 22:24:31 +11:00
parent 5be53acc72
commit a124089295
4 changed files with 76 additions and 33 deletions

View File

@ -1,17 +0,0 @@
.TH LINE 1
.SH NAME
line \- extract line from input
.SH SYNOPSIS
.B line
.IR ln
.SH DESCRIPTION
.B line
extracts the ln'th line from input provided over STDIN
.SH EXAMPLES
Get the 3rd line from the file line.1
.PP
.nf
.RS
line 3 < line.1
.RE
.fi

26
doc/lines.1 Normal file
View File

@ -0,0 +1,26 @@
.TH LINES 1
.SH NAME
line \- extract lines from input
.SH SYNOPSIS
.B line
.IR [LINES...]
.SH DESCRIPTION
.B line
extracts lines from stdin. If multiple lines are provided, they will be sorted
numerically. If the same line is specified twice, it will only be extracted
once.
.SH EXAMPLES
Get the 3rd line from the file line.1
.PP
.nf
.RS
line 3 < line.1
.RE
.fi
Get the 3rd, 4th and 5th lines from the file line.1
.PP
.nf
.RS
line 3 5 4 < line.1
.RE
.fi

View File

@ -26,40 +26,73 @@ const char *argv0;
void
usage()
{
die("usage: %s ln", argv0);
die("usage: %s [LINE...]", argv0);
}
int
getlineno(const char *s)
{
int ln;
char *p;
ln = (int)strtol(s, &p, 10);
if (errno != 0 || *p != '\0' || ln <= 0) {
errno ? edie("strtol: ") : die("unable to parse line");
}
return ln;
}
/* Insert ln into lns, assuming it is lns_size long and 0 initialised */
int *
insertln(int ln, int *lns, size_t lns_size)
{
int *ip = lns;
int j;
while (lns_size && *ip && *ip < ln) {
ADVANCE_PTR(ip, lns_size);
}
while (lns_size) {
j = *ip;
*ip = ln;
ln = j;
ADVANCE_PTR(ip, lns_size);
}
return lns;
}
/* Print the ln'th line from fp to stdout */
void
line(FILE *fp, int ln)
printlines(FILE *fp, int *lns, size_t lns_size)
{
char c;
int cln = 1;
while ((c = fgetc(fp)) != '\0') {
if (cln > ln) break;
if (cln == ln) putc(c, stdout);
while (lns_size && (c = fgetc(fp)) != '\0') {
if (cln > *lns) { ADVANCE_PTR(lns, lns_size); }
if (cln == *lns) putc(c, stdout);
if (c == '\n') cln++;
}
}
/* Print a specified line from stdin */
/* Print specified lines from stdin */
int
main(int argc, char *argv[])
{
int *lns;
SET_ARGV0();
if (argc < 1) usage();
int ln;
char *p;
ln = (int)strtol(argv[0], &p, 10);
if (errno != 0 || *p != '\0') {
errno ? edie("strtol: ") : die("unable to parse ln");
size_t lns_size = argc;
lns = ecalloc(lns_size, sizeof(int));
while (argc) {
lns = insertln(getlineno(argv[0]), lns, lns_size);
SHIFT_ARGS();
}
SHIFT_ARGS();
FILE *fp;
fp = fdopen(STDIN_FILENO, "r");
line(fp, ln);
printlines(fp, lns, lns_size);
return 0;
}

View File

@ -1,7 +1,8 @@
/* SEE COPYRIGHT NOTICE IN util.c */
#define SHIFT_ARGS() argv++; argc--;
#define SET_ARGV0() argv0 = argv[0]; SHIFT_ARGS();
#define ADVANCE_PTR(ptr, size) (ptr)++; (size)--
#define SHIFT_ARGS() ADVANCE_PTR(argv, argc)
#define SET_ARGV0() argv0 = argv[0]; SHIFT_ARGS();
void die(const char *fmt, ...);
void edie(const char *fmt, ...);