Compare commits

...

21 Commits

Author SHA1 Message Date
Tibor Bizjak b0f766e725 chapter 03 excercise partial solution 2023-07-26 14:17:04 +02:00
Tibor Bizjak d40f20afb7 complete rewrite. the previous implementetion was incorrect, not all occurences
of pattern were found (eg. xy in xxy).
2023-07-25 16:55:19 +02:00
Tibor Bizjak 09fb685153 fixed implementation error; not all matches were found (e.g. xy in xxy)
there is no optimization, the book version is used thus the rename
2023-07-23 23:25:29 +02:00
Tibor Bizjak 8ebefb2974 changed find loop 2023-07-23 14:04:29 +02:00
Tibor Bizjak bd26ae43a5 renamed files 2023-07-23 12:24:13 +02:00
Tibor Bizjak 291e9e87ec changed k&r naming scheme, renamed files 2023-07-23 12:22:28 +02:00
Tibor Bizjak 3fd2a66b17 rewrote part of program for lower complexity 2023-07-23 12:13:43 +02:00
Tibor Bizjak 11e44def75 implemented optional argument flags 2023-07-22 16:09:12 +02:00
Tibor Bizjak 3c529c1b9b added optional argument flag parsing 2023-07-22 15:07:45 +02:00
Tibor Bizjak ff3df46f36 refractored 04-find.c to seperate compilation units 2023-07-22 14:17:28 +02:00
Tibor Bizjak ee037ecf6f updated k&r .gitignore, now tracks nested directories 2023-07-22 14:14:34 +02:00
Tibor Bizjak 70a6cd85ab renamed grep to find, starting refractoring 2023-07-20 15:50:52 +02:00
Tibor Bizjak 2b9c7e9bcb date converter excercise 2023-07-20 15:31:38 +02:00
Tibor Bizjak 44774f3582 moved #includes 2023-07-19 11:21:16 +02:00
Tibor Bizjak 4efe1541d0 Removed unnecessary variable from readlines, fixed bug where
EOF terminated line was skipped
2023-07-19 11:17:23 +02:00
Tibor Bizjak a481bec3ba rewrote readlines 2023-07-18 23:48:37 +02:00
Tibor Bizjak 9df28e0ec9 k&r section 5.6 excercise solution 2023-07-18 22:22:18 +02:00
Tibor Bizjak ee59768555 k&r section 5.5 excercise solutions 2023-07-18 16:43:22 +02:00
Tibor Bizjak e6de3d1193 fixed parsef, exponent can now follow integer part 2023-07-17 12:44:19 +02:00
Tibor Bizjak bcff42f74d moved error handling to appropriate header files 2023-07-16 13:31:57 +02:00
Tibor Bizjak b127575211 forgot to remove T arg from UNARY_T_FUN macro 2023-07-16 13:26:38 +02:00
21 changed files with 821 additions and 245 deletions

6
.gitignore vendored
View File

@ -16,8 +16,12 @@
!k\&r/[0-9]*/
# and excercise solutions
!k\&r/*/[0-9]*.c
!k\&r/*/[0-9]*/
!k\&r/*/[0-9]*/*.c
# do ignore _ prefixed files
k\&r/**/_*
# and header files
!k\&r/*/*.h
!k\&r/**/*.h
# ---- udemy c++ .gitignore ----
# except udemy cpp

View File

@ -3,8 +3,10 @@
#define STACK_H
#define printerr(format, ...) printf("error: " format "\n", ##__VA_ARGS__)
/* ERROR MESSAGES */
#define EMPTY_STACK_ERR "stack empty"
#define SHORT_STACK_ERR "not enough elements on stack"
#define FULL_STACK_ERR "stack full, can't push %g"
#ifndef MAX_STACK
#define MAX_STACK 100

View File

@ -4,15 +4,11 @@
#include <assert.h>
#define MAX_STACK 100
#include "04-glob-stack.h"
#include "04-tokens.h"
#include "global-stack.h"
#include "tokens.h"
/* --------- ERROR MESSAGES */
#define printerr(format, ...) printf("error: " format "\n", ##__VA_ARGS__)
#define ZERODIV_ERR "zero divisor"
#define DOMAIN_ERR "operand not in domain [%d, %d]"
#define NEG_ERR "negative operand %g"
#define FULL_STACK_ERR "stack full, can't push %g"
#define UNKNOWN_TOKEN_ERR "unknown token %s"
#define VAR_NOT_SET_ERR "variable %c has no value"
@ -192,27 +188,25 @@ char * parsef(char s[], double *x)
int sign = SIGN(s);
ATOI(s, *x);
#define X(sep) *s != sep &&
if (DEC_SEP 1) {
*x *= sign;
return s;
int exp = 0;
/* fractional part */
#define X(sep) *s == sep ||
if (DEC_SEP 0) {
s++;
ATOI(s, *x, exp--);
*x *= pow(10, exp);
}
*x *= sign;
#undef X
/* exponent part */
#define X(sep) *s == sep ||
if (EXP_SEP 0) {
s++;
sign = SIGN(s);
exp = 0;
ATOI(s, exp);
*x *= pow(10, sign * exp);
}
#undef X
s++;
/* fractional part */
int exp = 0;
ATOI(s, *x, exp--);
*x *= sign * pow(10, exp);
#define X(sep) *s != sep &&
if (EXP_SEP 1)
return s;
#undef X
s++;
/* exponent */
sign = SIGN(s);
exp = 0;
ATOI(s, exp);
*x *= pow(10, sign * exp);
return s;
}

View File

@ -2,6 +2,13 @@
#define TOKENS_H
#include <math.h>
#define printerr(format, ...) printf("error: " format "\n", ##__VA_ARGS__)
/* ERROR MESSAGES */
#define ZERODIV_ERR "zero divisor"
#define DOMAIN_ERR "operand not in domain [%d, %d]"
#define NEG_ERR "negative operand %g"
/* --------- CALCULATOR FUNCTION TYPES */
/* the following macros allow us to call native c constructs
* in a declarative style */
@ -18,7 +25,7 @@
/* unary function */
#define UNARY_FUN(F) push(F(pop()))
/* unary function with tests */
#define UNARY_T_FUN(F, T, ...) \
#define UNARY_T_FUN(F, ...) \
do { double op = pop(); __VA_ARGS__ push(F(op)); } while (0)
/* commutative function */
#define COMM_FUN(F) push(F(pop(), pop()))
@ -89,4 +96,5 @@
OPERATORS \
MATH_H_BINDINGS
#undef printerr
#endif // TOKENS_H

View File

@ -0,0 +1,47 @@
#include <stdio.h>
#define MAXLINE 1000 /* maximum input line length */
int getln(char line[], int lim);
int strindex(char source[], char searchfor[]);
/* find: prints lines containing pattern, returns number of matching lines */
int find(char *pattern, char lineno_flag, char except_flag)
{
char line[MAXLINE];
int found = 0;
long lineno;
for (lineno = 1; getln(line, MAXLINE) > 0; lineno++)
if ((strindex(line, pattern) >= 0) != except_flag) {
if (lineno_flag)
printf("%ld:", lineno);
printf("%s", line);
found++;
}
return found;
}
/* getline: get line (including \n) into s, return length */
int getln(char *s, int lim)
{
int c, i = 0;
while (--lim > 0 && (c = getchar()) != EOF && (s[i++] = c) != '\n')
;
s[i] = '\0';
return i;
}
/* strindex: return index of t in s, -1 if none */
int strindex(char s[], char t[])
{
int i, j, k;
for (i = 0; s[i]; i++) {
for (j=i, k=0; t[k] && s[j] == t[k]; j++, k++)
;
if (k > 0 && !t[k])
return i;
}
return -1;
}

View File

@ -0,0 +1,132 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#define BUFF_BITS 10
#define BUFF_SIZE (1 << BUFF_BITS)
/* buffered_ln: structure for buffered input line */
struct buffered_ln {
unsigned long lineno; /* line number */
unsigned int len; /* line length */
char self[BUFF_SIZE]; /* line buffer */
int last_char; /* last read char of line
when equals to EOF or \n the line
has been read to completion */
};
void init_bln(struct buffered_ln *);
int get_bln(struct buffered_ln *);
void flush_bln(struct buffered_ln *);
int sub_of_bln(const char *pattern, struct buffered_ln *, unsigned plen);
/* find: finds occurences of pattern in input lines */
int find(char *pattern, char lineno_flag, char except_flag)
{
size_t plen = strlen(pattern);
if (plen-1 > BUFF_SIZE) {
printf("error: length of pattern > max line\n");
return -1;
}
struct buffered_ln bln;
init_bln(&bln);
while (get_bln(&bln))
if (sub_of_bln(pattern, &bln, plen) == !except_flag) {
if (lineno_flag)
printf("%ld:", bln.lineno);
flush_bln(&bln);
}
}
/* init_bln: initalizes buffered line struct */
void init_bln(struct buffered_ln *bln)
{
bln->lineno = 0;
bln->len = 0;
bln->last_char = '\n';
}
#define OVERFLOW_MASK (~0 << BUFF_BITS)
#define INDEX_MASK (~OVERFLOW_MASK)
#define bln_i(i) ((i) & INDEX_MASK) /* casts unsigned integer i to a valid bln index */
#define overflowed_bln(bln) (bln->len & OVERFLOW_MASK) /* 1 if bln is overflowed */
/* eol_bln: 1 if bln si finalized (last_char is \n or EOF) */
#define eol_bln(bln) (bln->last_char == EOF || bln->last_char == '\n')
#define bln_next_i(bln) bln_i(bln->len) /* next writable index of bln */
#define bln_start_i(bln) (overflowed_bln(bln) ? bln_next_i(bln) : 0) /* starting index of bln */
/* getchar_bln: gets char from input and writes it to bln, returns it */
#define getchar_bln(bln) \
(bln->self[bln_next_i(bln)] = bln->last_char, ++bln->len, bln->last_char = getchar())
/* get_bln: skips current line in buffer line bln, sets bln to next line of input
* returns 0 on EOF and a postivie value otherwise */
int get_bln(struct buffered_ln *bln)
{
/* finalize previous line */
while (!eol_bln(bln))
bln->last_char = getchar();
if (bln->last_char == EOF)
return 0;
/* init next line */
bln->lineno++;
bln->len = 0;
return (bln->last_char = getchar()) != EOF;
}
/* flush_bln: flushes buffered line bln to stdout */
void flush_bln(struct buffered_ln *bln)
{
unsigned i;
/* print overflowed chars */
if (overflowed_bln(bln)) {
for (i = BUFF_SIZE; i < bln->len; i++)
putchar('.');
for (i = bln_next_i(bln); i < BUFF_SIZE; i++)
putchar(bln->self[i]);
}
/* print buffered chars */
for (i = 0; i < bln_next_i(bln); i++)
putchar(bln->self[i]);
/* print not yet read chars */
for (; !eol_bln(bln); bln->last_char = getchar())
putchar(bln->last_char);
putchar('\n');
}
/* sub_of_bln: returns 0 if pattern with length plen is not a substring of
* buffered line bln and a positive value otherwise */
int sub_of_bln(const char *pattern, struct buffered_ln *bln, const unsigned plen)
{
/* buffered line must not be overflowed */
assert(!overflowed_bln(bln));
/* fill buffer with plen-1 chars */
for (; bln->len < plen-1; getchar_bln(bln))
if (eol_bln(bln))
return 0;
unsigned i, j;
int k;
/* handle buffered chars */
for (i = plen-1; i < bln->len; i++) {
for (j = i, k = plen-1; k >= 0 && bln->self[j] == pattern[k]; k--, j--)
;
if (k < 0)
return 1;
}
/* handle no yet read chars */
for (; !eol_bln(bln); getchar_bln(bln)) {
if (bln->last_char != pattern[plen-1])
continue;
for (j = bln_i(bln_next_i(bln)-1), k = plen-2; k >=0 && bln->self[j] == pattern[k]; k--, j = bln_i(j-1))
;
if (k < 0)
return 1;
}
return 0;
}

View File

@ -0,0 +1,63 @@
#include <stdio.h>
/* compile with find-no-overflow.c or find-opt.c
* gcc main.c [find-no-overflow.c | find-opt.c] */
int find(char *pattern, char lineno_flag, char except_flag);
#define ARG_FLAGS X('n', lineno) X('x', except)
/* find pattern given by first arg in lines and print them
* takes optional flags
* -x : print all except matching
* -n : print line numbers */
int main(int argc, char *argv[])
{
int i;
char c;
/* declare flag variables */
#define X(c, flag) char flag##_flag = 0;
ARG_FLAGS
#undef X
char **parg = argv;
/* parse flag arguments */
for (i = 1; *++parg; ) {
if (**parg != '-' || !(*parg)[1]) {
argv[i++] = *parg;
continue;
}
while (c = *++parg[0])
switch (c) {
#define X(C, flag) case C: flag##_flag = 1; break;
ARG_FLAGS
#undef X
default:
printf("error: illegal option -%c\n", c);
argc = 0;
break;
}
--argc;
}
/* illegal arguments */
if (argc != 2) {
printf("usage: find ");
#define X(c, _) printf("[-%c] ", c);
ARG_FLAGS
#undef X
printf("pattern\n");
return -1;
}
char *pattern = argv[1];
/* verify pattern */
for (i = 0; (c = pattern[i]) != '\0'; i++)
if (c == '\n') {
printf("error: newline in pattern\n");
return -2;
}
int found = find(pattern, lineno_flag, except_flag);
return found;
}

View File

@ -1,118 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <assert.h>
int grep(char pattern[]);
/* grep with graceful buffer overflow */
/* parse and verify arg pattern, pass it to grep */
int main(int argc, char *argv[])
{
/* verify arg is given */
if (argc < 2) {
printf("error: excpected pattern\n");
return -1;
}
char *pattern = argv[1];
/* verify pattern */
char c;
int i;
for (i = 0; (c = pattern[i]) != '\0'; i++)
if (c == '\n') {
printf("error: newline in pattern\n");
return -2;
}
int found = grep(pattern);
printf("found = %d\n", found);
return found;
}
void println(void);
int flush_lnbuff(void);
int getch_lnbuff(void);
/* grep: prints lines containing pattern, returns number of matching lines */
int grep(char *pattern)
{
int found, i, c;
const int plen = strlen(pattern);
i = found = 0;
while ((c = getch_lnbuff()) != EOF)
if (c != pattern[i])
i = 0;
else if (++i == plen) { // found match
i = 0;
found++;
flush_lnbuff();
println();
}
return found;
}
/* println: prints next line from stdin
* prints newline on EOF */
void println()
{
int c;
while ((c = getchar()) != EOF && c != '\n')
putchar(c);
putchar(c);
}
/* ------------------------ line buffer ---------------------- */
#define LNBUFF_LEN 128
/* the line buffer lenght must be a power of two */
static_assert(!(LNBUFF_LEN % 2), "Line buffer length is not a power of two!");
/* line_buffer: global overflowing line buffer */
struct {
char self[LNBUFF_LEN];
unsigned len;
} lnbuff = {.len= 0};
/* LNBUFF_I: current index in line buffer */
#define LNBUFF_I (lnbuff.len & (LNBUFF_LEN - 1))
/* getch_lnbuff: getchar and add it to buffer */
int getch_lnbuff()
{
int c = getchar();
if (c == EOF || c == '\n') // new line
lnbuff.len = 0;
else {
lnbuff.self[LNBUFF_I] = c;
lnbuff.len++;
}
return c;
}
/* flush_lnbuff: print contents of line buffer, return length */
int flush_lnbuff()
{
int i;
/* handle overflowing chars */
if (lnbuff.len > LNBUFF_LEN) {
for (i = LNBUFF_LEN; i < lnbuff.len; i++)
putchar('.');
for (i = LNBUFF_I; i < LNBUFF_LEN; i++)
putchar(lnbuff.self[i]);
}
/* handle rest of chars */
for (i = 0; i < LNBUFF_I; i++)
putchar(lnbuff.self[i]);
i = lnbuff.len;
lnbuff.len = 0;
return i;
}

View File

@ -1,15 +0,0 @@
#include <stdio.h>
#define W 80
#define REPEAT 4000000
int main()
{
int i, j;
for (i = 0; i < REPEAT; i++) {
for (j = 0; j < W; j++)
putchar('y');
putchar('\n');
}
return 0;
}

View File

@ -1,75 +0,0 @@
#include <stdio.h>
#include <string.h>
#define MAXLINE 1000 /* maximum input line length */
int grep(char *pattern);
/* somewhat optimized book version of grep */
/* find all lines matching pattern */
int main(int argc, char *argv[])
{
/* verify arg is given */
if (argc < 2) {
printf("error: excpected pattern\n");
return -1;
}
char *pattern = argv[1];
/* verify pattern */
char c;
int i;
for (i = 0; (c = pattern[i]) != '\0'; i++)
if (c == '\n') {
printf("error: newline in pattern\n");
return -2;
}
int found = grep(pattern);
printf("found = %d\n", found);
return found;
}
int getln(char line[], int lim);
int strindex(char source[], char searchfor[], int slen);
/* grep: prints lines containing pattern, returns number of matching lines */
int grep(char *pattern)
{
char line[MAXLINE];
int found = 0;
int slen = strlen(pattern);
while (getln(line, MAXLINE) > 0)
if (strindex(line, pattern, slen) >= 0) {
printf("%s", line);
found++;
}
return found;
}
/* getline: get line (including \n) into s, return length */
int getln(char *s, int lim)
{
int c, i = 0;
while (--lim > 0 && (c = getchar()) != EOF && (s[i++] = c) != '\n')
;
s[i] = '\0';
return i;
}
/* strindex: return index of t in s, -1 if none */
int strindex(char s[], char t[], int slen)
{
int i, j;
for (i = j = 0; s[i]; i++)
if (s[i] != t[j])
j = 0;
else if (++j == slen) { // found match
return i - slen + 1;
}
return -1;
}

View File

@ -0,0 +1,101 @@
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#include <math.h>
int getint(int *p);
int getfloat(float *p);
/* ungetchar: push char c back to input stream */
#define ungetchar(c) ungetc(c, stdin)
/* tests getfloat, prints input to output, puts valid numbers
* in brackets : n -> [n] */
int main()
{
float x;
int r;
while ((r = getfloat(&x)) != EOF)
if (!r) {
int c;
putchar(getchar());
while (!isdigit(c = getchar()) && c != EOF && c != '-' && c != '+')
putchar(c);
ungetchar(c);
} else
printf("[%g]", x);
return 0;
}
/* we assert that EOF is negative */
static_assert(EOF < 0, "EOF is not a negative number");
/* ugetint: gets unsigned int from input to n
* n must be intialized by caller
* takes optional arguments for loop increment
* last char read is stored in varvar_c */
#define ugetint(var_c, n, ...) \
do { \
for (; isdigit(var_c = getchar()); __VA_ARGS__) \
n = 10 * (n) + var_c - '0'; \
} while (0)
/* getint : gets int from input and overwrites it to p
* returns 1 on valid integer, 0 if no integer is found
* and EOF on EOF. */
int getint(int *p)
{
int c;
if ((c = getchar()) == EOF)
return EOF;
/* handle sign */
int sign = (c == '-') ? -1 : ((c == '+') ? 1 : 0);
if (sign)
c = getchar();
if (!isdigit(c)) { /* not a number */
ungetchar(c);
if (sign)
ungetchar((sign > 0) ? '+' : '-');
return 0;
}
*p = c - '0';
ugetint(c, *p);
ungetchar(c);
*p *= (sign) ? sign : 1;
return 1;
}
#define DEC_SEP X('.') X(',')
#define EXP_SEP X('e') X('E')
/* getfloat : gets float from input and overwrites it to p
* returns 1 on valid integer, 0 if no integer is found
* and EOF on EOF. */
int getfloat(float *p)
{
char flag;
int n;
if ((flag = getint(&n)) < 1) /* not a number */
return flag;
*p = n;
int exp, c = getchar();
/* fractional part */
#define X(C) c == C ||
if (DEC_SEP 0) {
n = exp = 0;
ugetint(c, n, exp--);
*p += n * pow(10, exp);
}
#undef X
/* exponent part */
#define X(C) c == C ||
if ((EXP_SEP 0) && getint(&exp)) {
*p *= pow(10, exp);
} else
ungetchar(c);
return 1;
}

View File

@ -0,0 +1,40 @@
#include <stdio.h>
char *strcat(char *s, const char *t);
char *strcpy(char *t, const char *s);
size_t strlen(const char *s);
/* passes args to strcat, prints result */
int main(int argc, char *argv[])
{
if (argc < 3)
return 1;
char s[strlen(argv[1]) + strlen(argv[2])];
strcat(strcpy(s, argv[1]), argv[2]);
printf("%s\n", s);
}
/* strcat: concat string t to end of string s */
char *strcat(char *s, const char *t)
{
int slen = strlen(s);
return strcpy(s + slen, t) - slen;
}
/* strcpy: copy string s to t */
char *strcpy(char *t, const char *s)
{
char *tc = t;
while ((*t++ = *s++))
;
return tc;
}
/* strlen: return length of string s (without \0) */
size_t strlen(const char *s)
{
const char *sc = s;
while (*s++)
;
return s - sc - 1;
}

View File

@ -0,0 +1,21 @@
#include <stdio.h>
#include <string.h>
int strend(const char *s, const char *t);
/* passes args to strend, prints result */
int main(int argc, char *argv[])
{
if (argc < 3)
return 1;
printf("%s\n", (strend(argv[1], argv[2])) ? "true" : "false");
return 0;
}
/* strend: returns 1 if t == end of s otherwise false */
int strend(const char *s, const char *t)
{
size_t s_len = strlen(s);
size_t t_len = strlen(t);
return (s_len >= t_len) && !strcmp(s + s_len - t_len, t);
}

View File

@ -0,0 +1,64 @@
#include <stdio.h>
#include <stdlib.h>
char *strncpy(char *t, const char *s, size_t n);
char *strncat(char *t, const char *s, size_t n);
int strncmp(const char *s, const char *t, size_t n);
/* strlen: returns string length (w/o '\0') */
size_t strlen(const char *s)
{
const char * const sc = s;
while (*s++)
;
return s - sc - 1;
}
/* takes args s1, s2, n and passes them to the above declared
* functions, prints the results */
int main(int argc, char *argv[])
{
if (argc < 4)
return 1;
int n = atoi(argv[3]);
char s[strlen(argv[1]) + strlen(argv[2]) + 1];
/* strncpy */
printf("strncpy: %s\n", strncpy(s, argv[1], n));
/* strncat */
printf("strncat: %s\n", strncat(s, argv[2], n));
/* strncmp */
int comp = strncmp(argv[1], argv[2], n);
printf("strncmp: %.*s ", n, argv[1]);
putchar((comp > 0) ? '>' : (comp < 0) ? '<' : '=');
printf(" %.*s\n", n, argv[2]);
return 0;
}
/* strncpy: copies at most n chars from s to t, returns t*/
char *strncpy(char *t, const char *s, size_t n)
{
char * const tc = t;
while (n-- && (*t++ = *s++))
;
*t = '\0';
return tc;
}
/* strncat: concats at most n chars of s to t, returns t */
char *strncat(char *t, const char *s, size_t n)
{
strncpy(t + strlen(t), s, n);
return t;
}
/* strncmp: compares at most n chars of s and t */
int strncmp(const char *s, const char *t, size_t n)
{
if (!n)
return 0;
while (--n && *s && (*s == *t))
s++, t++;
return *s - *t;
}

View File

@ -0,0 +1,109 @@
#include <stdio.h>
/* array bounds */
#define MAXLINES 100
#define BUFF_SIZE (80 * MAXLINES)
int readlines(char *lines[], int maxlines, char *ln_buff, size_t lb_size);
void writelines(char *lines[], int n);
void qsort_string(char *v[], int left, int right);
/* sorts lines from stdin and prints them */
int main()
{
char *lines[MAXLINES];
char buffer[BUFF_SIZE];
int line_count = readlines(lines, MAXLINES, buffer, BUFF_SIZE);
if (line_count < 0) {
line_count = -line_count - 1;
printf("warning: buffer overflow occured, read %d lines\n", line_count);
} else if (line_count > MAXLINES) {
line_count = MAXLINES;
printf("warning: too many lines, read %d lines\n", line_count);
}
qsort_string(lines, 0, line_count-1);
writelines(lines, line_count);
return 0;
}
/* ---------- reading/printing functions */
#include <assert.h>
#include <ctype.h>
/* writelines: prints n lines */
void writelines(char *lines[], int n)
{
while (n--)
printf("%s\n", *lines++);
}
/* readlines: reads lines from input, writing them to ln_buff
* and line pointers to lines.
* returns number of lines read,
* -lines_read-1 < 0 on buffer overflow
* maxlines+1 on lines overflow */
int readlines(char *lines[], int maxlines, char *buffer, size_t buff_size)
{
assert(maxlines > 0);
char ** const fst_line = lines;
int c, not_empty = 0;
for (*lines = buffer; (c = getchar()) != EOF && buff_size; --buff_size) {
not_empty |= !isspace(c);
if (c == '\n') {
if (!not_empty) { /* skip empty lines */
buff_size += buffer - *lines;
buffer = *lines;
continue;
}
not_empty = 0;
*buffer++ = '\0';
if (!--maxlines)
break;
*++lines = buffer;
} else
*buffer++ = c;
}
/* ignore trailing whitespace and empty lines */
while (c != EOF && isspace(c))
c = getchar();
if (c != EOF && !buff_size) /* buffer overflow, return -lines_read-1 */
return fst_line - lines - 1;
if (c != EOF && !maxlines) /* lines overflow, return maxlines+1 */
return lines - fst_line + 2;
return lines - fst_line + not_empty;
}
/* ---------- string quicksort */
#include <string.h>
void swap(char *v[], int i, int j);
/* qsort_string: sort v[left]...v[right] into increasing order */
void qsort_string(char *v[], int left, int right)
{
int i, last;
if (left >= right) /* do nothing if array contains */
return; /* fewer than two elements */
swap(v, left, (left + right)/2); /* move partition elem */
last = left; /* to v[0] */
for (i = left+1; i <= right; i++) /* partition */
if (strcmp(v[i], v[left]) < 0)
swap(v, ++last, i);
swap(v, left, last); /* restore partition elem */
qsort_string(v, left, last-1);
qsort_string(v, last+1, right);
}
/* swap: swap v[i] and v[j] */
void swap(char *v[], int i, int j)
{
char *temp = v[i];
v[i] = v[j], v[j] = temp;
}

View File

@ -0,0 +1,68 @@
#include <stdio.h>
#include <stdlib.h>
#define HELP_STR "usage: name year [month] day"
int month_day(int year, int day, int *pmonth);
int day_of_year(int year, int month, int day);
/* converts arguments year yearday to year month day or
* year month day to year yearday */
int main(int argc, char *argv[])
{
int y, m, d, yd;
if (argc == 3) { /* year day -> month day */
y = atoi(argv[1]), yd = atoi(argv[2]);
if ((d = month_day(y, yd, &m))) {
printf("%d %d %d\n", y, m, d);
return 0;
}
printf("error: invalid yearday %d\n", yd);
} else if (argc == 4) { /* year month day -> year day */
y = atoi(argv[1]), m = atoi(argv[2]), d = atoi(argv[3]);
if ((yd = day_of_year(y, m, d))) {
printf("%d %d\n", y, yd);
return 0;
}
printf("error: invalid month %d or day %d\n", m, d);
}
puts(HELP_STR);
return 1;
}
static char daytab[][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
#define IS_LEAP(Y) (Y%4 == 0 && Y%100 != 0 || Y%400 == 0)
#define IS_MONTH(M) (0 < M && M <= 12)
#define IS_D_OF_M(LEAP, M, D) (0 < D && D <= daytab[LEAP][M])
#define IS_YD_OF_Y(LEAP, YD) (0 < YD && YD <= 365+LEAP)
/* day_of_year: set day of year from month & day
* return day of year or 0 on error */
int day_of_year(int year, int month, int day)
{
int m, leap = IS_LEAP(year);
if (!IS_MONTH(month) || !IS_D_OF_M(leap, month, day))
/* validity check */
return 0;
for (m = 1; m < month; m++)
day += daytab[leap][m];
return day;
}
/* month_day: set month, day from day of year
* return day of month or 0 on error, set pmonth to month */
int month_day(int year, int yearday, int *pmonth)
{
int m, leap = IS_LEAP(year);
if (!IS_YD_OF_Y(leap, yearday)) /* validity check */
return 0;
for (m = 1; yearday > daytab[leap][m]; m++)
yearday -= daytab[leap][m];
*pmonth = m;
return yearday;
}

View File

@ -5,10 +5,12 @@
namespace Ad
{
namespace Constants
namespace Consts
{
constexpr std::int32_t EGO_VEHICLE_ID = -1;
constexpr std::size_t VEHICLES_PER_LANE = 2;
constexpr std::int8_t VISUALIZE_STEP = 20;
} // namespace Constants
} // namespace Ad

View File

@ -1,6 +1,8 @@
#include <cmath>
#include <cstdint>
#include <iostream>
#include <random>
#include <algorithm>
#include "AdConstants.h"
#include "AdFunctions.h"
@ -10,6 +12,7 @@ namespace Ad
namespace Utils
{
/* kph_to_mps: converts kmph to meters/second */
constexpr float kph_to_mps(const float kph)
{
return 0.2778 * kph;
@ -20,26 +23,131 @@ constexpr float kph_to_mps(const float kph)
namespace Data
{
/* init_ego_vehicle: initializes ego vehicle */
Types::Vehicle init_ego_vehicle()
{
return Types::Vehicle{
.id = Constants::EGO_VEHICLE_ID,
.id = Consts::EGO_VEHICLE_ID,
.lane = Types::Lane::Center,
.speed_mps = Utils::kph_to_mps(135),
.rel_distance_m = 0,
.rel_dist_m = 0,
};
}
/* init_vehicle_array: initialize an array of vehicles */
template <std::size_t N>
static void init_vehicle_array(std::array<Types::Vehicle, N> &arr, int32_t start_id, Types::Lane lane)
{
/* init random generators */
std::mt19937 rng(std::random_device{}());
std::uniform_real_distribution<double> speed(-150, 150);
std::uniform_real_distribution<double> dist_gen(0, Consts::VISUALIZE_STEP);
double dist = static_cast<double> (-Consts::VISUALIZE_STEP) * (arr.size() / 2 + 1);
for (int32_t i = 0; i < arr.size(); i++)
arr[i] = Types::Vehicle{
.id = start_id++,
.lane = lane,
.speed_mps = Utils::kph_to_mps(speed(rng)),
.rel_dist_m = (dist += Consts::VISUALIZE_STEP + dist_gen(rng))
};
}
/* init_vehicles: initializes vehicles */
Types::NeighborVehicles init_vehicles()
{
auto nv = Types::NeighborVehicles{};
int32_t id = 0;
init_vehicle_array(nv.left_lane, id, Types::Lane::Left);
init_vehicle_array(nv.center_lane, (id += nv.left_lane.size()), Types::Lane::Center);
init_vehicle_array(nv.right_lane, (id += nv.right_lane.size()), Types::Lane::Right);
return nv;
}
} // namespace Ad::Data
namespace Visualize
{
void print_vehicle(const Types::Vehicle vehicle)
/* print_lane: prints lane, helper function for print vehicle */
void print_lane(const Types::Lane lane)
{
#define if_lane(LANE) if (lane == Types::Lane::LANE) std::cout << #LANE; else
if_lane(Left)
if_lane(Center)
if_lane(Right)
/* else */
std::cout << "Unknown";
}
/* print_vehicle: prints vehicle */
void print_vehicle(const Types::Vehicle &vehicle)
{
std::cout << "Vehicle " << vehicle.id << '\n';
std::cout << "Lane : ";
print_lane(vehicle.lane);
std::cout << '\n';
std::cout << "speed : " << vehicle.speed_mps << " m/s\n";
std::cout << "distance : " << vehicle.rel_distance_m << " m\n";
std::cout << "distance : " << vehicle.rel_dist_m << " m\n";
}
/* print_vehicle_array: helper function for print_neghbor_vehicles */
template <size_t N>
static void print_vehicle_array(const std::array<Types::Vehicle, N> &arr)
{
for (int32_t i = 0; i < arr.size(); i++) {
print_vehicle(arr[i]);
std::cout << '\n';
}
}
/* print_neghbor_vehicles: print neghbor vehicles information */
void print_neighbor_vehicles(const Types::NeighborVehicles &vehicles)
{
print_vehicle_array(vehicles.left_lane);
print_vehicle_array(vehicles.center_lane);
print_vehicle_array(vehicles.right_lane);
}
/* print_scene: prints scene
* very rough implementation */
void print_scene(const Types::Vehicle &ego_vehicle,
const Types::NeighborVehicles &vehicles)
{
/* TODO : sort NeighborVehicles arrays */
double min_dist_d = std::min({vehicles.left_lane[0].rel_dist_m,
vehicles.center_lane[0].rel_dist_m,
vehicles.right_lane[0].rel_dist_m});
double max_dist_d = std::max({vehicles.left_lane.back().rel_dist_m,
vehicles.center_lane.back().rel_dist_m,
vehicles.right_lane.back().rel_dist_m});
int32_t min_dist = std::floor(min_dist_d / Consts::VISUALIZE_STEP) * Consts::VISUALIZE_STEP;
int32_t max_dist = std::ceil(max_dist_d / Consts::VISUALIZE_STEP) * Consts::VISUALIZE_STEP;
int32_t li, ci, ri, count;
li = ci = ri = Consts::VEHICLES_PER_LANE - 1;
std::cout << " L C R\n";
for (int32_t dist = max_dist; dist >= min_dist; dist -= Consts::VISUALIZE_STEP) {
printf("%8d| ", dist);
char c;
#define HANDLE_LANE(lane, li) \
for (count = 0; li >= 0 && vehicles.lane[li].rel_dist_m >= dist-Consts::VISUALIZE_STEP; count++, li--) \
; \
c = !count ? ' ' : (count > 1) ? '0' + count : (vehicles.lane[li+1].speed_mps >= 0) ? 'v' : '^'; \
std::cout << c << " | "
HANDLE_LANE(left_lane, li);
HANDLE_LANE(center_lane, ci);
HANDLE_LANE(right_lane, ri);
std::cout << '\n';
}
}
} // namespace Ad::Visualize

View File

@ -11,12 +11,18 @@ namespace Utils
namespace Data
{
Types::Vehicle init_ego_vehicle();
Types::Vehicle init_ego_vehicle();
Types::NeighborVehicles init_vehicles();
} // namespace Ad::Data
namespace Visualize
{
void print_vehicle(const Types::Vehicle vehicle);
} // namespace Ad::Visualize
void print_vehicle(const Types::Vehicle &vehicle);
void print_neighbor_vehicles(const Types::NeighborVehicles &vehicles);
void print_scene(const Types::Vehicle &ego_vehicle,
const Types::NeighborVehicles &vehicles);
} // namespace Ad::Visualize
} // namespace Ad

View File

@ -1,6 +1,7 @@
#pragma once
#include <cstdint>
#include <array>
#include "AdConstants.h"
@ -22,7 +23,14 @@ struct Vehicle
std::int32_t id;
Lane lane;
double speed_mps;
double rel_distance_m;
double rel_dist_m;
};
struct NeighborVehicles
{
std::array<Vehicle, Consts::VEHICLES_PER_LANE> left_lane;
std::array<Vehicle, Consts::VEHICLES_PER_LANE> center_lane;
std::array<Vehicle, Consts::VEHICLES_PER_LANE> right_lane;
};
} // namespace Ad::Types

View File

@ -8,7 +8,14 @@
int main()
{
auto ego_vehicle = Ad::Data::init_ego_vehicle();
auto vehicles = Ad::Data::init_vehicles();
Ad::Visualize::print_vehicle(ego_vehicle);
std::cout << '\n';
Ad::Visualize::print_neighbor_vehicles(vehicles);
Ad::Visualize::print_scene(ego_vehicle, vehicles);
return 0;
}