initial commit

This commit is contained in:
Connor Lane Smith 2011-05-23 02:36:34 +01:00
commit 8e26716a5a
23 changed files with 632 additions and 0 deletions

21
LICENSE Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,3 @@
/* See LICENSE file for copyright and license details. */
void eprintf(const char *, ...);

28
wc.1 Normal file
View 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
View 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);
}