Added pobj test files.
This commit is contained in:
parent
d69a1878b9
commit
99f85eb9c4
2 changed files with 480 additions and 0 deletions
412
test/pobj/calendar.c
Normal file
412
test/pobj/calendar.c
Normal file
|
@ -0,0 +1,412 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "pobj.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
#define MAXLINELEN 255
|
||||
|
||||
#define SUN 0
|
||||
#define MON 1
|
||||
#define TUE 2
|
||||
#define WED 3
|
||||
#define THU 4
|
||||
#define FRI 5
|
||||
#define SAT 6
|
||||
|
||||
#define DAILY 0
|
||||
#define MONTHLY 1
|
||||
#define WEEKLY 2
|
||||
#define ONCE 3
|
||||
#define COMMENT 4
|
||||
|
||||
#define PSET_INDEX(x, y, z) pobj_memcpy(x, x + y, &z, sizeof(z))
|
||||
#define PSET_STATIC(x, y) pobj_static_set_ref(&x, y)
|
||||
|
||||
struct string {
|
||||
char *data;
|
||||
int len;
|
||||
};
|
||||
|
||||
struct entry {
|
||||
int month;
|
||||
int day;
|
||||
char dayofweek;
|
||||
char type;
|
||||
struct string *text;
|
||||
struct entry *next;
|
||||
};
|
||||
|
||||
int string_ref_fields[] = {
|
||||
member_offset(struct string, data),
|
||||
-1
|
||||
};
|
||||
|
||||
int entry_ref_fields[] = {
|
||||
member_offset(struct entry, text),
|
||||
member_offset(struct entry, next),
|
||||
-1
|
||||
};
|
||||
|
||||
typedef struct string String;
|
||||
typedef struct entry Entry;
|
||||
|
||||
Entry *head = NULL;
|
||||
Entry *tail = NULL;
|
||||
|
||||
// Assumes input is non-persistent.
|
||||
void trim(String *s) {
|
||||
int i;
|
||||
for (i = 0; i < s->len && s->data[i] == ' '; i++) {
|
||||
s->data++;
|
||||
}
|
||||
s->len -= i;
|
||||
for (i = s->len - 1; i >= 0 && s->data[i] == ' '; i--) {
|
||||
s->len--;
|
||||
}
|
||||
s->data[s->len] = '\0';
|
||||
}
|
||||
|
||||
int findWordEnd(String *s, int start) {
|
||||
int end;
|
||||
while (s->data[start] == ' ') start++;
|
||||
for (end = start; end < s->len && s->data[end] != ' '; end++);
|
||||
return end < s->len ? end : s->len;
|
||||
}
|
||||
|
||||
// Assumes there is enough space in the destination.
|
||||
void persistentStringCopy(String *src, int off1, String *dst, int off2, int length) {
|
||||
/* int i; */
|
||||
/* char c = '\0'; */
|
||||
/* // Can't use strncpy here without some sort of pobj_update() function. */
|
||||
/* for (i = 0; i < length; i++) { */
|
||||
/* PSET_INDEX(dst->data, off2 + i, src->data[off1 + i]); */
|
||||
/* } */
|
||||
debug("in persistent string copy, src = %x, off1 = %d, dst = %x, off2 = %d, length = %d", src, off1, dst, off2, length);
|
||||
debug("src->len is %d, data at src->data[off1] = %s", src->len, src->data + off1);
|
||||
strncpy(dst->data + off2, src->data + off1, length);
|
||||
dst->data[off2+length] = '\0';
|
||||
pobj_update(dst->data);
|
||||
POBJ_SET_INT(dst, len, length);
|
||||
debug("end of copy, dst->data = %s, dst->len = %d", dst->data, dst->len);
|
||||
}
|
||||
|
||||
String *makePersistentString(String *s, int start, int len) {
|
||||
pobj_start();
|
||||
String *p = (String *) pobj_malloc(sizeof(String));
|
||||
pobj_ref_typify(p, string_ref_fields);
|
||||
POBJ_SET_REF(p, data, pobj_malloc(sizeof(char) * (len + 1)));
|
||||
persistentStringCopy(s, start, p, 0, len);
|
||||
pobj_end();
|
||||
return p;
|
||||
}
|
||||
|
||||
Entry *makeEntry(String *s, char t, int off) {
|
||||
Entry *e = (Entry *) pobj_malloc(sizeof(Entry));
|
||||
pobj_ref_typify(e, entry_ref_fields);
|
||||
POBJ_SET_CHAR(e, type, t);
|
||||
s = makePersistentString(s, off, s->len - off);
|
||||
POBJ_SET_REF(e, text, s);
|
||||
return e;
|
||||
}
|
||||
|
||||
Entry *makeCommentEntry(String *s) {
|
||||
pobj_start();
|
||||
Entry *e = makeEntry(s, COMMENT, 0);
|
||||
pobj_end();
|
||||
return e;
|
||||
}
|
||||
|
||||
Entry *makeDayEntry(String *s, int off) {
|
||||
pobj_start();
|
||||
Entry *e = makeEntry(s, DAILY, off);
|
||||
pobj_end();
|
||||
return e;
|
||||
}
|
||||
|
||||
Entry *makeMonthEntry(String *s, int d, int off) {
|
||||
pobj_start();
|
||||
Entry *e = makeEntry(s, MONTHLY, off);
|
||||
POBJ_SET_INT(e, day, d);
|
||||
pobj_end();
|
||||
return e;
|
||||
}
|
||||
|
||||
Entry *makeWeekEntry(String *s, int start, int off) {
|
||||
pobj_start();
|
||||
Entry *e = makeEntry(s, WEEKLY, off);
|
||||
switch (s->data[start]) {
|
||||
case 'm':
|
||||
POBJ_SET_CHAR(e, dayofweek, MON);
|
||||
break;
|
||||
case 't':
|
||||
switch (s->data[start+1]) {
|
||||
case 'u':
|
||||
POBJ_SET_CHAR(e, dayofweek, TUE);
|
||||
break;
|
||||
default:
|
||||
POBJ_SET_CHAR(e, dayofweek, THU);
|
||||
}
|
||||
break;
|
||||
case 'w':
|
||||
POBJ_SET_CHAR(e, dayofweek, WED);
|
||||
break;
|
||||
case 'f':
|
||||
POBJ_SET_CHAR(e, dayofweek, FRI);
|
||||
break;
|
||||
default:
|
||||
switch (s->data[start+1]) {
|
||||
case 'a':
|
||||
POBJ_SET_CHAR(e, dayofweek, SAT);
|
||||
break;
|
||||
default:
|
||||
POBJ_SET_CHAR(e, dayofweek, SUN);
|
||||
}
|
||||
}
|
||||
pobj_end();
|
||||
return e;
|
||||
}
|
||||
|
||||
Entry *makeOnceEntry(String *s, int m, int d, int off) {
|
||||
pobj_start();
|
||||
Entry *e = makeEntry(s, ONCE, off);
|
||||
POBJ_SET_INT(e, month, m);
|
||||
POBJ_SET_INT(e, day, d);
|
||||
pobj_end();
|
||||
return e;
|
||||
}
|
||||
|
||||
// Parse a (non-persistent) string into a (persistent) entry.
|
||||
Entry *parse(String *s) {
|
||||
int start, end, tmp;
|
||||
trim(s);
|
||||
if (s->data[0] == '#' || s->len < 1) {
|
||||
return makeCommentEntry(s);
|
||||
}
|
||||
start = 0;
|
||||
end = findWordEnd(s, start);
|
||||
switch (s->data[0]) {
|
||||
case 'D':
|
||||
return makeDayEntry(s, end + 1);
|
||||
case 'M':
|
||||
start = end;
|
||||
end = findWordEnd(s, start);
|
||||
return makeMonthEntry(s, atoi(s->data + start), end + 1);
|
||||
case 'W':
|
||||
start = end;
|
||||
end = findWordEnd(s, start);
|
||||
return makeWeekEntry(s, start + 1, end + 1);
|
||||
case 'O':
|
||||
start = end;
|
||||
end = findWordEnd(s, start);
|
||||
tmp = atoi(s->data + start);
|
||||
start = end;
|
||||
end = findWordEnd(s, start);
|
||||
return makeOnceEntry(s, tmp, atoi(s->data + start), end + 1);
|
||||
default:
|
||||
return makeCommentEntry(s);
|
||||
}
|
||||
}
|
||||
|
||||
// Should be rewritten to be sorted?
|
||||
void addEntry(String *str) {
|
||||
Entry *e = parse(str);
|
||||
pobj_start();
|
||||
if (head == NULL) {
|
||||
PSET_STATIC(head, e);
|
||||
} else {
|
||||
POBJ_SET_REF(tail, next, e);
|
||||
}
|
||||
PSET_STATIC(tail, e);
|
||||
POBJ_SET_REF(e, next, NULL);
|
||||
pobj_end();
|
||||
}
|
||||
|
||||
void print(Entry *e) {
|
||||
//e->text->data[e->text->len] = '\0';
|
||||
printf("%s\n", e->text->data);
|
||||
}
|
||||
|
||||
void findEntries(int month, int day, int dayofweek) {
|
||||
Entry *tmp = head;
|
||||
Entry *prev = NULL;
|
||||
while (tmp != NULL) {
|
||||
switch (tmp->type) {
|
||||
case DAILY:
|
||||
print(tmp);
|
||||
break;
|
||||
case MONTHLY:
|
||||
if (day == tmp->day) {
|
||||
print(tmp);
|
||||
}
|
||||
break;
|
||||
case WEEKLY:
|
||||
if (dayofweek == tmp->dayofweek) {
|
||||
print(tmp);
|
||||
}
|
||||
break;
|
||||
case ONCE:
|
||||
if (day == tmp->day && month == tmp->month) {
|
||||
print(tmp);
|
||||
// Remove this entry, since it is no longer needed.
|
||||
pobj_start();
|
||||
if (prev == NULL) {
|
||||
PSET_STATIC(head, tmp->next);
|
||||
} else {
|
||||
POBJ_SET_REF(prev, next, tmp->next);
|
||||
}
|
||||
if (tail == tmp) {
|
||||
PSET_STATIC(tail, prev);
|
||||
}
|
||||
pobj_free(tmp);
|
||||
pobj_end();
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = tmp;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
void getEntries(String *str) {
|
||||
time_t timer;
|
||||
struct tm asdf;
|
||||
struct tm *stm = &asdf;
|
||||
debug("1");
|
||||
time(&timer);
|
||||
debug("2");
|
||||
localtime_r(&timer, stm);
|
||||
debug("3");
|
||||
findEntries(stm->tm_mon + 1, stm->tm_mday, stm->tm_wday);
|
||||
}
|
||||
|
||||
void dumpEntries(String *str) {
|
||||
Entry *tmp = head;
|
||||
while (tmp != NULL) {
|
||||
switch (tmp->type) {
|
||||
case DAILY:
|
||||
printf("DAILY ");
|
||||
break;
|
||||
case MONTHLY:
|
||||
printf("MONTHLY %d ", tmp->day);
|
||||
break;
|
||||
case WEEKLY:
|
||||
printf("WEEKLY ");
|
||||
switch (tmp->dayofweek) {
|
||||
case SUN:
|
||||
printf("sun ");
|
||||
break;
|
||||
case MON:
|
||||
printf("mon ");
|
||||
break;
|
||||
case TUE:
|
||||
printf("tue ");
|
||||
break;
|
||||
case WED:
|
||||
printf("wed ");
|
||||
break;
|
||||
case THU:
|
||||
printf("thu ");
|
||||
break;
|
||||
case FRI:
|
||||
printf("fri ");
|
||||
break;
|
||||
default:
|
||||
printf("sat ");
|
||||
}
|
||||
break;
|
||||
case ONCE:
|
||||
printf("ONCE %d %d ", tmp->month, tmp->day);
|
||||
break;
|
||||
default:
|
||||
printf("COMMENT ");
|
||||
}
|
||||
print(tmp);
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
int getline(char *string, int num) {
|
||||
if (fgets(string, num, stdin) != string) {
|
||||
return -1;
|
||||
}
|
||||
num = strlen(string);
|
||||
if (string[num-1] == '\n') {
|
||||
string[num-1] = '\0';
|
||||
return num - 1;
|
||||
} else {
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
void error(char *a, char *b, int len) {
|
||||
b[len] = '\0';
|
||||
printf("%s%s\n", a, b);
|
||||
}
|
||||
|
||||
void process(String *str) {
|
||||
int end = findWordEnd(str, 0);
|
||||
str->data += end;
|
||||
str->len -= end;
|
||||
switch (str->data[-end]) {
|
||||
case 'A':
|
||||
addEntry(str);
|
||||
break;
|
||||
case 'G':
|
||||
getEntries(str);
|
||||
break;
|
||||
case 'D':
|
||||
dumpEntries(str);
|
||||
break;
|
||||
default:
|
||||
error("Unknown command: ", str->data - end, end);
|
||||
}
|
||||
}
|
||||
|
||||
void usage() {
|
||||
printf("Simple calendar program. Reads in commands from stdin.\n\n");
|
||||
printf("Commands:\n");
|
||||
printf("A <entry> -- adds the specified entry into the calendar\n");
|
||||
printf(" <entry> can be of one of the following forms:\n");
|
||||
printf(" DAILY <message> -- denotes that <message> should be printed every day\n");
|
||||
printf(" WEEKLY <wday> <message> -- denotes that <message> should be printed on the\n");
|
||||
printf(" specified day of the week\n");
|
||||
printf(" <wday> must be one of sun, mon, tue, wed, thu, fri, and sat\n");
|
||||
printf(" MONTHLY <mday> <message> -- denotes that <message> should be printed on the\n");
|
||||
printf(" specified day of the month\n");
|
||||
printf(" <mday> must be a number between 1 and 31, inclusive\n");
|
||||
printf(" ONCE <mon> <mday> <message> -- denotes that <message> should be only\n");
|
||||
printf(" printed on the specified date\n");
|
||||
printf(" <mon> must be a number between 1 and 12, inclusive\n");
|
||||
printf(" <mday> must be a number between 1 and 31, inclusive\n");
|
||||
printf(" All other entries are interpreted as comments.\n");
|
||||
printf("G -- displays the messages for the current day\n");
|
||||
printf(" deletes ONCE type entries for current day\n");
|
||||
printf("D -- dumps all entries currently in the calendar\n");
|
||||
printf("<EOF> -- exits the program\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char line[MAXLINELEN+1];
|
||||
String str;
|
||||
str.data = line;
|
||||
if (argc > 1 && !strncmp(argv[1], "--help", 6)) {
|
||||
usage();
|
||||
return 0;
|
||||
} else if (argc > 1) {
|
||||
error("Illegal option: ", argv[1], strlen(argv[1]));
|
||||
return 1;
|
||||
}
|
||||
pobj_init(NULL);
|
||||
while ((str.len = getline(line, MAXLINELEN)) != -1) {
|
||||
process(&str);
|
||||
str.data = line; // Could have been moved by process().
|
||||
}
|
||||
pobj_shutdown();
|
||||
return 0;
|
||||
}
|
||||
|
68
test/pobj/stringlist.c
Normal file
68
test/pobj/stringlist.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "pobj.h"
|
||||
|
||||
struct node {
|
||||
char *str;
|
||||
struct node *next;
|
||||
};
|
||||
|
||||
int node_ref_fields[] = {
|
||||
member_offset(struct node, str),
|
||||
member_offset(struct node, next),
|
||||
-1
|
||||
};
|
||||
|
||||
typedef struct node Node;
|
||||
|
||||
Node *list = NULL;
|
||||
|
||||
int getline(char *string, int num) {
|
||||
if (fgets(string, num, stdin) != string) {
|
||||
return -1;
|
||||
}
|
||||
num = strlen(string);
|
||||
if (string[num-1] == '\n') {
|
||||
string[num-1] = '\0';
|
||||
return num - 1;
|
||||
} else {
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
void process(char *line) {
|
||||
int len = strlen(line);
|
||||
Node *tmp = (Node *) pobj_malloc(sizeof(Node));
|
||||
char *cpy = (char *) pobj_malloc(sizeof(char) * (len + 1));
|
||||
pobj_ref_typify(tmp, node_ref_fields);
|
||||
strcpy(cpy, line);
|
||||
pobj_update(cpy);
|
||||
pobj_set_ref(tmp, (void **) &(tmp->str), cpy);
|
||||
pobj_set_ref(tmp, (void **) &(tmp->next), list);
|
||||
pobj_static_set_ref(&list, tmp);
|
||||
}
|
||||
|
||||
void print() {
|
||||
int i = 1;
|
||||
Node *tmp = list;
|
||||
printf("Entries: \n");
|
||||
while (tmp != NULL) {
|
||||
printf("%d. %s\n", i++, tmp->str);
|
||||
tmp = tmp->next;
|
||||
}
|
||||
printf("Done.\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
/* static Node *list = NULL; */
|
||||
char line[256];
|
||||
pobj_init(NULL);
|
||||
/* if (pobj_init() == 0) { */
|
||||
while ((getline(line, 255)) != -1) {
|
||||
process(line);
|
||||
}
|
||||
/* } */
|
||||
print();
|
||||
pobj_shutdown();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue