diff --git a/test/pobj/calendar.c b/test/pobj/calendar.c new file mode 100644 index 0000000..de505b5 --- /dev/null +++ b/test/pobj/calendar.c @@ -0,0 +1,412 @@ +#include +#include +#include +#include +#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 -- adds the specified entry into the calendar\n"); + printf(" can be of one of the following forms:\n"); + printf(" DAILY -- denotes that should be printed every day\n"); + printf(" WEEKLY -- denotes that should be printed on the\n"); + printf(" specified day of the week\n"); + printf(" must be one of sun, mon, tue, wed, thu, fri, and sat\n"); + printf(" MONTHLY -- denotes that should be printed on the\n"); + printf(" specified day of the month\n"); + printf(" must be a number between 1 and 31, inclusive\n"); + printf(" ONCE -- denotes that should be only\n"); + printf(" printed on the specified date\n"); + printf(" must be a number between 1 and 12, inclusive\n"); + printf(" 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(" -- 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; +} + diff --git a/test/pobj/stringlist.c b/test/pobj/stringlist.c new file mode 100644 index 0000000..37fa189 --- /dev/null +++ b/test/pobj/stringlist.c @@ -0,0 +1,68 @@ +#include +#include +#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; +}