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:
parent
5be53acc72
commit
a124089295
17
doc/line.1
17
doc/line.1
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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, ...);
|
||||
|
|
Loading…
Reference in New Issue