commit 6fff651

Emilia Smólska  ·  2026-06-20 11:38:20 +0000 UTC
parent 6fff651
foo
5 files changed,  +273, -0
A dice.1
A dice.c
A mac.h
+3, -0
1@@ -0,0 +1,3 @@
2+dice
3+*.o
4+*.core
+36, -0
 1@@ -0,0 +1,36 @@
 2+.POSIX:
 3+.SUFFIXES:
 4+
 5+CC=cc
 6+CFLAGS=-g
 7+LDFLAGS=-Wl,-w
 8+LDLIBS=
 9+STDCFLAGS=-std=c23
10+WCFLAGS=-Wall -Wextra -Wpedantic
11+
12+PREFIX=/usr/local
13+BINDIR=${DESTDIR}${PREFIX}/bin
14+MANDIR=${DESTDIR}${PREFIX}/man
15+MAN1=${MANDIR}/man1
16+
17+PROG=dice
18+MAN=dice.1
19+OBJS=dice.o
20+
21+all: ${PROG}
22+
23+${PROG}: ${OBJS}
24+	${CC} ${LDFLAGS} -o ${PROG} ${OBJS} ${LDLIBS}
25+
26+.SUFFIXES: .c .o
27+.c.o:
28+	${CC} ${CFLAGS} ${STDCFLAGS} ${WCFLAGS} -c -o $@ $<
29+
30+${OBJS}: mac.h
31+
32+clean:
33+	rm -f ${PROG} *.o *.core
34+
35+install: all
36+	cp ${PROG} ${BINDIR}/
37+	cp ${MAN} ${MAN1}/
A dice.1
+40, -0
 1@@ -0,0 +1,40 @@
 2+.Dd $Mdocdate$
 3+.Dt DICE 1
 4+.Os
 5+.Sh NAME
 6+.Nm dice
 7+.Nd dice roller and coin flipper
 8+.Sh SYNOPSIS
 9+.Nm
10+.Op Fl csq
11+.Op Ar expr
12+.Sh DESCRIPTION
13+The
14+.Nm
15+utility displays pseudorandom results of specified dice roll or coinflip
16+expressions. It accepts the following flags:
17+.Bl -tag -width Ds
18+.It Fl c
19+Flip a coin, displaying
20+.Dq heads
21+or
22+.Dq tails .
23+.It Fl s
24+Parse a line read from standard input instead of
25+.Ar expr .
26+.It Fl q
27+Don't display
28+.Ar expr
29+followed by an equals sign before the result.
30+.El
31+If neither
32+.Fl c
33+or
34+.Fl s
35+are specified,
36+.Ar expr
37+is a required argument.
38+.Sh EXIT STATUS
39+.Ex -std
40+.Sh SEE ALSO
41+.Xr random 6
A dice.c
+135, -0
  1@@ -0,0 +1,135 @@
  2+/*
  3+ * Public domain software
  4+ * Dedicated to Stephen Bourne
  5+ */
  6+
  7+#include <stdarg.h>
  8+#include <stdio.h>
  9+#include <stdlib.h>
 10+#include <string.h>
 11+#include <time.h>
 12+#include <unistd.h>
 13+
 14+#include "mac.h"
 15+
 16+TYPE STRUCT DICE
 17+{
 18+	INT	ndic;
 19+	INT	nsid;
 20+	CONST STRUCT DICE	*next;
 21+} DICE;
 22+
 23+STATIC STRING	argv0;
 24+STATIC BOOL	cflag,sflag,qflag;
 25+
 26+NORETURN STATIC VOID	usage();
 27+NORETURN STATIC VOID	error(STRING, ...);
 28+STATIC VOID	initrand();
 29+STATIC VOID	initargv0(STRING);
 30+STATIC CONST DICE	*parsedice(STRING);
 31+STATIC STRING	getlin();
 32+STATIC INT	rolldice(CONST DICE *);
 33+STATIC VOID	coinflip();
 34+STATIC VOID	*xmalloc(SIZE);
 35+
 36+INT
 37+main(INT argc, CHAR **argv)
 38+{
 39+	initargv0(argv[0]); initrand();
 40+	INT ch; WHILE (ch=getopt(argc,argv,"csq"))!=-1
 41+	DO	SWITCH ch IN
 42+		CASE 'c':	cflag=TRUE; BREAK;
 43+		CASE 's':	sflag=TRUE; BREAK;
 44+		CASE 'q':	qflag=TRUE; BREAK;
 45+		OUT:	usage();
 46+		ENDSW;
 47+	OD; argc-=optind; argv+=optind;
 48+	IF cflag THEN coinflip(); RETURN 0 FI;
 49+	STRING e;
 50+	IF sflag THEN e=getlin() ELIF argc<1 THEN usage() ELSE e=argv[0] FI;
 51+	AUTO d=parsedice(e);
 52+	IF NOT qflag THEN printf("%s=",e) FI; printf("%d\n",rolldice(d));
 53+	RETURN 0;
 54+}
 55+
 56+STATIC VOID
 57+initrand()
 58+{
 59+	srandom(time(NIL)+getpid());
 60+}
 61+
 62+NORETURN STATIC VOID
 63+usage()
 64+{
 65+	fprintf(STDERR,"usage: %s [-csq] [expr]\n",argv0);
 66+	exit(1);
 67+}
 68+
 69+NORETURN STATIC VOID
 70+error(STRING fmt, ...)
 71+{
 72+	fprintf(STDERR,"%s: ",argv0);
 73+	VALIST	ap;
 74+	va_start(ap, fmt);
 75+	vfprintf(STDERR,fmt,ap);
 76+	fputc('\n',STDERR);
 77+	va_end(ap);
 78+	exit(1);
 79+}
 80+
 81+STATIC VOID
 82+initargv0(STRING s)
 83+{
 84+	argv0=strrchr(s,'/'); IF NOT argv0 THEN argv0=s ELSE argv0++ FI;
 85+}
 86+
 87+STATIC CONST DICE *
 88+parsedice(STRING e)
 89+{
 90+	CHAR *end;
 91+	DICE *p=xmalloc(SIZEOF(DICE));
 92+	IF NOT *e THEN error("expected number of dice") FI;
 93+	p->ndic=strtol(e,&end,10); e=end;
 94+	IF *e++!='d' THEN error("expected `d' in expression") FI;
 95+	IF NOT *e THEN error("expected number of sides") FI;
 96+	p->nsid=strtol(e,&end,10); e=end;
 97+	IF p->nsid==0 THEN error("can't have zero-sided die") FI;
 98+	IF NOT *e
 99+	THEN	RETURN p
100+	ELIF *e++!='+'
101+	THEN	error("expected `+' in expression")
102+	FI;
103+	p->next=parsedice(e); RETURN p;
104+}
105+
106+STATIC STRING
107+getlin()
108+{
109+	CHAR *buf=xmalloc(80);
110+	IF NOT fgets(buf,80,STDIN) THEN buf[0]=0 FI;
111+	buf[strcspn(buf,"\n")]=0;
112+	RETURN buf;
113+}
114+
115+STATIC INT
116+rolldice(CONST DICE *dice)
117+{
118+	INT	res=0;
119+	FOR AUTO d=dice; d; d=d->next
120+	DO	FOR INT i=0; i<d->ndic; i++ DO res+=random()%d->nsid+1 OD;
121+	OD;
122+	RETURN res;
123+}
124+
125+STATIC VOID
126+coinflip()
127+{
128+	IF random()&1 THEN printf("heads\n") ELSE printf("tails\n") FI;
129+}
130+
131+STATIC VOID *
132+xmalloc(SIZE n)
133+{
134+	VOID *p=malloc(n); IF NOT p THEN abort() FI;
135+	RETURN memset(p,0,n);
136+}
A mac.h
+59, -0
 1@@ -0,0 +1,59 @@
 2+#define IF	if(
 3+#define THEN	){
 4+#define ELIF	;}else if(
 5+#define ELSE	;}else{
 6+#define FI	;}
 7+
 8+#define FOR	for(
 9+#define WHILE	while(
10+#define DO	){
11+#define OD	;}
12+#define BREAK	break
13+#define CONTINUE	continue
14+
15+#define SWITCH	switch(
16+#define IN	){
17+#define CASE	case
18+#define OUT	default
19+#define ENDSW	;}
20+
21+#define CONST	const
22+#define VOLATILE	volatile
23+#define EXTERN	extern
24+#define STATIC	static
25+#define RETURN	return
26+#define SIZEOF	sizeof
27+
28+#define TYPE	typedef
29+#define STRUCT	struct
30+#define UNION	union
31+#define ENUM	enum
32+
33+#define AUTO	auto
34+typedef int	INT;
35+typedef long	LONG;
36+typedef void	VOID;
37+typedef char	CHAR;
38+typedef bool	BOOL;
39+typedef size_t	SIZE;
40+typedef const char	*STRING;
41+typedef va_list	VALIST;
42+
43+#define TRUE	true
44+#define FALSE	false
45+
46+#define ANDF	&&
47+#define ORF	||
48+
49+#define NOT	!
50+#define OR	|
51+#define AND	&
52+#define XOR	^
53+
54+#define NIL	((VOID *)0)
55+
56+#define STDIN	stdin
57+#define STDOUT	stdout
58+#define STDERR	stderr
59+
60+#define NORETURN	[[noreturn]]