initial commit
This commit is contained in:
commit
8e26716a5a
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT/X Consortium License
|
||||||
|
|
||||||
|
© 2011 Connor Lane Smith <cls@lubutu.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
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 AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
31
Makefile
Normal file
31
Makefile
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
include config.mk
|
||||||
|
|
||||||
|
SRC = basename.c cat.c echo.c false.c grep.c tee.c touch.c true.c wc.c
|
||||||
|
OBJ = $(SRC:.c=.o) util.o
|
||||||
|
BIN = $(SRC:.c=)
|
||||||
|
MAN = $(SRC:.c=.1)
|
||||||
|
|
||||||
|
all: $(BIN)
|
||||||
|
|
||||||
|
$(OBJ): util.h
|
||||||
|
$(BIN): util.o
|
||||||
|
|
||||||
|
.o:
|
||||||
|
@echo CC -o $@
|
||||||
|
@$(CC) -o $@ $< util.o $(LDFLAGS)
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
@echo CC -c $<
|
||||||
|
@$(CC) -c $< $(CFLAGS)
|
||||||
|
|
||||||
|
dist: clean
|
||||||
|
@echo creating dist tarball
|
||||||
|
@mkdir -p sbase-$(VERSION)
|
||||||
|
@cp LICENSE Makefile config.mk $(SRC) $(MAN) util.c util.h sbase-$(VERSION)
|
||||||
|
@tar -cf sbase-$(VERSION).tar sbase-$(VERSION)
|
||||||
|
@gzip sbase-$(VERSION).tar
|
||||||
|
@rm -rf sbase-$(VERSION)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo cleaning
|
||||||
|
@rm -f $(BIN) $(OBJ)
|
14
basename.1
Normal file
14
basename.1
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.TH BASENAME 1 sbase\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
basename \- strip directory from filename
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B basename
|
||||||
|
.I string
|
||||||
|
.RI [ suffix ]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B basename
|
||||||
|
prints to stdout the
|
||||||
|
.I string
|
||||||
|
with any leading directory components, and the
|
||||||
|
.IR suffix ,
|
||||||
|
removed.
|
30
basename.c
Normal file
30
basename.c
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *str = argv[1];
|
||||||
|
size_t n, i = 0;
|
||||||
|
|
||||||
|
if(argc < 2)
|
||||||
|
eprintf("usage: %s string [suffix]\n", argv[0]);
|
||||||
|
if(str[0] != '\0')
|
||||||
|
for(i = strlen(str)-1; i > 0 && str[i] == '/'; i--)
|
||||||
|
str[i] = '\0';
|
||||||
|
if(i == 0 || !(str = strrchr(argv[1], '/')))
|
||||||
|
str = argv[1];
|
||||||
|
else
|
||||||
|
str++;
|
||||||
|
|
||||||
|
if(argc > 2 && strlen(str) > strlen(argv[2])) {
|
||||||
|
n = strlen(str) - strlen(argv[2]);
|
||||||
|
if(!strcmp(&str[n], argv[2]))
|
||||||
|
str[n] = '\0';
|
||||||
|
}
|
||||||
|
puts(str);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
10
cat.1
Normal file
10
cat.1
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
.TH CAT 1 sbase\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
cat \- concatenate files
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B cat
|
||||||
|
.RI [ files ...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B cat
|
||||||
|
reads each file in sequence and writes it to stdout. If no file is given, cat
|
||||||
|
reads from stdin.
|
36
cat.c
Normal file
36
cat.c
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static void cat(FILE *, const char *);
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if(argc == 1)
|
||||||
|
cat(stdin, "<stdin>");
|
||||||
|
else for(i = 1; i < argc; i++) {
|
||||||
|
if(!(fp = fopen(argv[i], "r")))
|
||||||
|
eprintf("fopen %s:", argv[i]);
|
||||||
|
cat(fp, argv[i]);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cat(FILE *fp, const char *str)
|
||||||
|
{
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
while((n = fread(buf, 1, sizeof buf, fp)) > 0)
|
||||||
|
if(fwrite(buf, 1, n, stdout) != n)
|
||||||
|
eprintf("<stdout>: write error:");
|
||||||
|
if(ferror(fp))
|
||||||
|
eprintf("%s: read error:", str);
|
||||||
|
}
|
9
config.mk
Normal file
9
config.mk
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# sbase version
|
||||||
|
VERSION = 0.0
|
||||||
|
|
||||||
|
CC = cc
|
||||||
|
#CC = musl-gcc
|
||||||
|
|
||||||
|
CPPFLAGS = -D_BSD_SOURCE
|
||||||
|
CFLAGS = -Os -ansi -Wall -pedantic $(CPPFLAGS)
|
||||||
|
LDFLAGS = -s -static
|
14
echo.1
Normal file
14
echo.1
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.TH ECHO 1 sbase\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
echo \- print arguments
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B echo
|
||||||
|
.RB [ \-n ]
|
||||||
|
.RI [ string ...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B echo
|
||||||
|
prints its arguments to stdout, separated by spaces and terminated by a newline.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.B \-n
|
||||||
|
Do not print terminating newline.
|
23
echo.c
Normal file
23
echo.c
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
bool nflag = false;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(argc > 1 && !strcmp(argv[1], "-n"))
|
||||||
|
nflag = true;
|
||||||
|
for(i = nflag ? 2 : 1; i < argc; i++) {
|
||||||
|
fputs(argv[i], stdout);
|
||||||
|
if(i+1 < argc)
|
||||||
|
fputc(' ', stdout);
|
||||||
|
}
|
||||||
|
if(!nflag)
|
||||||
|
fputc('\n', stdout);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
8
false.1
Normal file
8
false.1
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
.TH FALSE 1 sbase\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
false \- return failure
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B false
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B false
|
||||||
|
returns with a status code indicating failure.
|
8
false.c
Normal file
8
false.c
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
43
grep.1
Normal file
43
grep.1
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
.TH GREP 1 sbase\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
grep \- search files for a pattern
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B grep
|
||||||
|
.RB [ \-c ]
|
||||||
|
.RB [ \-i ]
|
||||||
|
.RB [ \-l ]
|
||||||
|
.RB [ \-n ]
|
||||||
|
.RB [ \-q ]
|
||||||
|
.RB [ \-v ]
|
||||||
|
.I pattern
|
||||||
|
.RI [ file ...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B grep
|
||||||
|
searches the input files for lines that match the pattern, a regular expression as defined in
|
||||||
|
.BR regex (7).
|
||||||
|
By default each matching line is printed to stdout. If no file is given, grep
|
||||||
|
reads from stdin.
|
||||||
|
.P
|
||||||
|
The status code is 0 if any lines match, and 1 if not. If an error occurred the
|
||||||
|
status code is 2.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.B \-c
|
||||||
|
prints only a count of matching lines.
|
||||||
|
.TP
|
||||||
|
.B \-i
|
||||||
|
matches lines case insensitively.
|
||||||
|
.TP
|
||||||
|
.B \-l
|
||||||
|
prints only the names of files with matching lines.
|
||||||
|
.TP
|
||||||
|
.B \-n
|
||||||
|
prefixes each matching line with its line number in the input.
|
||||||
|
.TP
|
||||||
|
.B \-q
|
||||||
|
prints nothing, only returns status.
|
||||||
|
.TP
|
||||||
|
.B \-v
|
||||||
|
selects lines which do
|
||||||
|
.B not
|
||||||
|
match the pattern.
|
97
grep.c
Normal file
97
grep.c
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <regex.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static void grep(FILE *, const char *, regex_t *);
|
||||||
|
|
||||||
|
static bool iflag = false;
|
||||||
|
static bool vflag = false;
|
||||||
|
static bool many;
|
||||||
|
static bool match = false;
|
||||||
|
static char mode = 0;
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i, flags = 0;
|
||||||
|
regex_t preg;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
for(i = 1; i < argc; i++)
|
||||||
|
if(!strcmp(argv[i], "-c"))
|
||||||
|
mode = 'c';
|
||||||
|
else if(!strcmp(argv[i], "-i"))
|
||||||
|
iflag = true;
|
||||||
|
else if(!strcmp(argv[i], "-l"))
|
||||||
|
mode = 'l';
|
||||||
|
else if(!strcmp(argv[i], "-n"))
|
||||||
|
mode = 'n';
|
||||||
|
else if(!strcmp(argv[i], "-q"))
|
||||||
|
mode = 'q';
|
||||||
|
else if(!strcmp(argv[i], "-v"))
|
||||||
|
vflag = true;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(i == argc) {
|
||||||
|
fprintf(stderr, "usage: %s [-c] [-i] [-l] [-n] [-v] pattern [files...]\n", argv[0]);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
if(mode == 'c')
|
||||||
|
flags |= REG_NOSUB;
|
||||||
|
if(iflag)
|
||||||
|
flags |= REG_ICASE;
|
||||||
|
regcomp(&preg, argv[i++], flags);
|
||||||
|
|
||||||
|
many = (argc > i+1);
|
||||||
|
if(i == argc)
|
||||||
|
grep(stdin, "<stdin>", &preg);
|
||||||
|
else for(; i < argc; i++) {
|
||||||
|
if(!(fp = fopen(argv[i], "r"))) {
|
||||||
|
fprintf(stderr, "fopen %s: ", argv[i]);
|
||||||
|
perror(NULL);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
grep(fp, argv[i], &preg);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
return match ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
grep(FILE *fp, const char *str, regex_t *preg)
|
||||||
|
{
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
int n, c = 0;
|
||||||
|
|
||||||
|
for(n = 1; fgets(buf, sizeof buf, fp); n++) {
|
||||||
|
if(regexec(preg, buf, 0, NULL, 0) ^ vflag)
|
||||||
|
continue;
|
||||||
|
if(mode == 'c')
|
||||||
|
c++;
|
||||||
|
else if(mode == 'l') {
|
||||||
|
puts(str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(mode == 'q')
|
||||||
|
exit(0);
|
||||||
|
else {
|
||||||
|
if(many)
|
||||||
|
printf("%s:", str);
|
||||||
|
if(mode == 'n')
|
||||||
|
printf("%d:", n);
|
||||||
|
fputs(buf, stdout);
|
||||||
|
}
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
if(mode == 'c')
|
||||||
|
printf("%d\n", c);
|
||||||
|
if(ferror(fp)) {
|
||||||
|
fprintf(stderr, "%s: read error: ", str);
|
||||||
|
perror(NULL);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
}
|
14
tee.1
Normal file
14
tee.1
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.TH TEE 1 sbase\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
tee \- duplicate stdin
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B tee
|
||||||
|
.RB [ \-a ]
|
||||||
|
.RI [ file ...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B tee
|
||||||
|
writes from stdin to stdout, making copies in each file.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.B \-a
|
||||||
|
append to each file rather than overwriting.
|
36
tee.c
Normal file
36
tee.c
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
bool aflag = false;
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
int i, nfps = 1;
|
||||||
|
size_t n;
|
||||||
|
FILE **fps;
|
||||||
|
|
||||||
|
if(argc > 1 && !strcmp(argv[1], "-a"))
|
||||||
|
aflag = true;
|
||||||
|
if(!(fps = malloc(sizeof *fps)))
|
||||||
|
eprintf("malloc:");
|
||||||
|
fps[nfps-1] = stdout;
|
||||||
|
|
||||||
|
for(i = aflag ? 2 : 1; i < argc; i++) {
|
||||||
|
if(!(fps = realloc(fps, ++nfps * sizeof *fps)))
|
||||||
|
eprintf("realloc:");
|
||||||
|
if(!(fps[nfps-1] = fopen(argv[i], aflag ? "a" : "w")))
|
||||||
|
eprintf("fopen %s:", argv[i]);
|
||||||
|
}
|
||||||
|
while((n = fread(buf, 1, sizeof buf, stdin)) > 0)
|
||||||
|
for(i = 0; i < nfps; i++)
|
||||||
|
if(fwrite(buf, 1, n, fps[i]) != n)
|
||||||
|
eprintf("%s: write error:", buf);
|
||||||
|
if(ferror(stdin))
|
||||||
|
eprintf("<stdin>: read error:");
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
22
touch.1
Normal file
22
touch.1
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
.TH TOUCH 1 sbase\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
touch \- set files' modification time
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B touch
|
||||||
|
.RB [ \-c ]
|
||||||
|
.RB [ \-t
|
||||||
|
.IR time ]
|
||||||
|
.RI [ file ...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B touch
|
||||||
|
sets the files' modification time to the current time. If a file does not exist
|
||||||
|
it is created.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.B \-c
|
||||||
|
do not create files if they do not exist.
|
||||||
|
.TP
|
||||||
|
.BI \-t " time"
|
||||||
|
sets the files' modification time to
|
||||||
|
.IR time ,
|
||||||
|
given as the number of seconds since the Unix epoch.
|
58
touch.c
Normal file
58
touch.c
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static void touch(const char *);
|
||||||
|
|
||||||
|
static bool cflag = false;
|
||||||
|
static time_t t;
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
t = time(NULL);
|
||||||
|
|
||||||
|
for(i = 1; i < argc; i++)
|
||||||
|
if(!strcmp(argv[i], "-c"))
|
||||||
|
cflag = true;
|
||||||
|
else if(!strcmp(argv[i], "-t") && i+1 < argc)
|
||||||
|
t = strtol(argv[++i], NULL, 0);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
for(; i < argc; i++)
|
||||||
|
touch(argv[i]);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
touch(const char *str)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct stat st;
|
||||||
|
struct utimbuf ut;
|
||||||
|
|
||||||
|
if(stat(str, &st) < 0) {
|
||||||
|
if(errno != ENOENT)
|
||||||
|
eprintf("stat %s:", str);
|
||||||
|
if(cflag)
|
||||||
|
return;
|
||||||
|
if((fd = creat(str, O_RDONLY|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0)
|
||||||
|
eprintf("creat %s:", str);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
ut.actime = st.st_atime;
|
||||||
|
ut.modtime = t;
|
||||||
|
if(utime(str, &ut) < 0)
|
||||||
|
eprintf("utime %s:", str);
|
||||||
|
}
|
8
true.1
Normal file
8
true.1
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
.TH TRUE 1 sbase\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
true \- return success
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B true
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B true
|
||||||
|
returns with a status code indicating success.
|
8
true.c
Normal file
8
true.c
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
22
util.c
Normal file
22
util.c
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
eprintf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if(fmt[0] && fmt[strlen(fmt)-1] == ':') {
|
||||||
|
fputc(' ', stderr);
|
||||||
|
perror(NULL);
|
||||||
|
}
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
3
util.h
Normal file
3
util.h
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
|
||||||
|
void eprintf(const char *, ...);
|
28
wc.1
Normal file
28
wc.1
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
.TH WC 1 sbase\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
wc \- word count
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B wc
|
||||||
|
.RB [ \-c ]
|
||||||
|
.RB [ \-l ]
|
||||||
|
.RB [ \-m ]
|
||||||
|
.RB [ \-w ]
|
||||||
|
.RI [ file ...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B wc
|
||||||
|
prints the number of lines, words, and bytes in each file. If any flags are
|
||||||
|
given, wc will print only the requested information. If no files are given, wc
|
||||||
|
reads stdin.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.B \-c
|
||||||
|
print the number of bytes.
|
||||||
|
.TP
|
||||||
|
.B \-l
|
||||||
|
print the number of lines.
|
||||||
|
.TP
|
||||||
|
.B \-m
|
||||||
|
print the number of characters, not bytes.
|
||||||
|
.TP
|
||||||
|
.B \-w
|
||||||
|
print the number of words.
|
89
wc.c
Normal file
89
wc.c
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static void output(const char *, long, long, long);
|
||||||
|
static void wc(FILE *, const char *);
|
||||||
|
|
||||||
|
static bool lflag = false;
|
||||||
|
static bool wflag = false;
|
||||||
|
static char cmode = 0;
|
||||||
|
static long tc = 0, tl = 0, tw = 0;
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
bool many;
|
||||||
|
int i;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
for(i = 1; i < argc; i++)
|
||||||
|
if(!strcmp(argv[i], "-c"))
|
||||||
|
cmode = 'c';
|
||||||
|
else if(!strcmp(argv[i], "-l"))
|
||||||
|
lflag = true;
|
||||||
|
else if(!strcmp(argv[i], "-m"))
|
||||||
|
cmode = 'm';
|
||||||
|
else if(!strcmp(argv[i], "-w"))
|
||||||
|
wflag = true;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
many = (argc > i+1);
|
||||||
|
|
||||||
|
if(i == argc)
|
||||||
|
wc(stdin, NULL);
|
||||||
|
else for(; i < argc; i++) {
|
||||||
|
if(!(fp = fopen(argv[i], "r")))
|
||||||
|
eprintf("fopen %s:", argv[i]);
|
||||||
|
wc(fp, argv[i]);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
if(many)
|
||||||
|
output("total", tc, tl, tw);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
output(const char *str, long nc, long nl, long nw)
|
||||||
|
{
|
||||||
|
bool noflags = !cmode && !lflag && !wflag;
|
||||||
|
|
||||||
|
if(lflag || noflags)
|
||||||
|
printf(" %5ld", nl);
|
||||||
|
if(wflag || noflags)
|
||||||
|
printf(" %5ld", nw);
|
||||||
|
if(cmode || noflags)
|
||||||
|
printf(" %5ld", nc);
|
||||||
|
if(str)
|
||||||
|
printf(" %s", str);
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wc(FILE *fp, const char *str)
|
||||||
|
{
|
||||||
|
bool word = false;
|
||||||
|
char c;
|
||||||
|
long nc = 0, nl = 0, nw = 0;
|
||||||
|
|
||||||
|
while((c = fgetc(fp)) != EOF) {
|
||||||
|
if(cmode != 'm' || (c & 0xc0) != 0x80)
|
||||||
|
nc++;
|
||||||
|
if(c == '\n')
|
||||||
|
nl++;
|
||||||
|
if(!isspace(c))
|
||||||
|
word = true;
|
||||||
|
else if(word) {
|
||||||
|
word = false;
|
||||||
|
nw++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tc += nc;
|
||||||
|
tl += nl;
|
||||||
|
tw += nw;
|
||||||
|
output(str, nc, nl, nw);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user