/* * lexer.c: Reads in the .calendar files */ #include #include #include "cal_struct.h" #define opener "[" #define closer "]" #define VersionMajor 2 GSList *eventlist; void print_glist(gpointer data, gpointer user_data) { struct event *myevent = (struct event*)data; if (data == NULL) return; printf ("===============================================\nNew event\n"); printf ("Start: %s %02d:%02d End: %s %02d:%02d\n", myevent->start.date, myevent->start.time / 60, myevent->start.time % 60, myevent->end.date, myevent->end.time / 60, myevent->end.time % 60); printf ("Contents: %s\n", myevent->description); printf ("Repeat = %d (%d)", (int)(myevent->repeat), myevent->repeatcount); } int skip_chars(FILE *fp, char *terminator) { int c; int cnt; cnt = 0; while( (c = fgetc(fp)) != EOF) { if (c == terminator[cnt]) { cnt++; if (terminator[cnt] == '\0') return TRUE; } else cnt = 0; } return FALSE; } int peek_char(FILE *fp, char *c) { if ( ((*c) = fgetc(fp)) != EOF) { ungetc((*c), fp); return TRUE; } else return FALSE; } int skip_whitespace(FILE *fp) { int c; while( (c = fgetc(fp)) != EOF) if (!isspace(c)) { ungetc(c, fp); return TRUE; } return FALSE; } int get_until(FILE *fp, char terminator, char *buf) { int c; while( (c = fgetc(fp)) != EOF) { if (c == terminator) { *buf = '\0'; return TRUE; } *buf = (char)c; buf++; } *buf = '\0'; return FALSE; } int get_number(FILE *fp, int *x) { char buf[50]; int c; int cnt; cnt = 0; buf[cnt] = '\0'; while( (c= fgetc(fp)) != EOF) { if (!isdigit(c)) { ungetc(c, fp); *x = atoi(buf); return TRUE; } buf[cnt++] = (char)c; buf[cnt] = '\0'; } *x = atoi(buf); return FALSE; } /* Get string until EOF or closer_char */ int get_string(FILE *fp, char *string) { int c; int cnt; cnt = 0; while ( (c = fgetc(fp)) != EOF) { if (c == closer[0]) { string[cnt] = '\0'; ungetc((char)c, fp); return TRUE; } string[cnt++] = (char)c; } return FALSE; } int get_dates(FILE *fp, char *keyword, struct event *ptr) { char *c; int x; if (strncmp("Single", keyword, 6) == 0) { ptr->repeat = Single; /* It's a single date */ if (! skip_whitespace(fp) || !get_until(fp, ' ', ptr->start.date)) return FALSE; if (! skip_chars(fp, "End")) return FALSE; return TRUE; } else if (strncmp("Days", keyword, 4) == 0) { ptr->repeat = Days; if (! skip_whitespace(fp) || !get_until(fp, ' ', ptr->start.date)) return FALSE; if (! skip_whitespace(fp) || !get_number(fp, &(ptr->repeatcount))) return FALSE; if (! skip_chars(fp, "End")) return FALSE; return TRUE; } return FALSE; } int getid(FILE *fp, char *string) { int c; int cnt; cnt = 0; while( (c =fgetc(fp)) != EOF) { if (isalnum(c)) string[cnt++] = (char)c; else { string[cnt] = '\0'; return TRUE; } } string[cnt] = '\0'; return FALSE; } int parse_appointment(FILE *fp, struct event *ptr, char keyword[]) { char buf[50]; int x,y,c; if (strcmp(keyword, "Start") == 0) { if ( ! skip_whitespace(fp) || ! get_number(fp, &x) ) { g_error("Unable to get start time"); return FALSE; } g_print ("Appointment start = %02d:%02d\n", x/60, x % 60); ptr->start.time = x; return TRUE; } if (strcmp(keyword, "Length") == 0) { if ( ! skip_whitespace(fp) || ! get_number(fp, &x) ) { g_error("Unable to get length"); return FALSE; } g_print ("Appointment length = %d\n", x); ptr->end.time = ptr->start.time + x; return TRUE; } if (strcmp(keyword, "Alarms") == 0) { while(TRUE) { skip_whitespace(fp); if (!peek_char(fp, (char*)&c)) { g_error("Cannot read alarm list"); return FALSE; } if (!isdigit(c)) break; if (! get_number(fp, &x)) return FALSE; g_print("New alarm %d\n", x); } return TRUE; } g_print("Unknown keyword %s\n", keyword); return FALSE; } int parse_item(FILE *fp, struct event *ptr, char keyword[]) { char buf[50]; int x, y, c; if (strcmp(keyword, "Remind") == 0) { if (! skip_whitespace(fp) || ! get_number(fp, &x)) { g_error("Cannot get remind level"); return FALSE; } g_print("Remind level = %d\n", x); return TRUE; } if (strcmp(keyword, "Owner") == 0) { if (!get_string(fp, buf)) { g_error("Cannot get owner information"); return FALSE; } g_print("Owner = %s\n", buf); return TRUE; } if (strcmp(keyword, "Uid") == 0) { if (!skip_whitespace(fp) || !get_until(fp, *closer, buf)) { g_error("Cannot get unique ID"); return FALSE; } g_print("UID = %s\n", buf); return TRUE; } if (strcmp(keyword, "Contents") == 0) { if (!get_string(fp, buf)) { g_error("Cannot get item text"); return FALSE; } g_print("Contents = %s\n", buf); strcpy(ptr->description,buf); return TRUE; } if (strcmp(keyword, "Text") == 0) { if (! skip_whitespace(fp) || ! get_number(fp, &x) || (x < 0) || ! skip_whitespace(fp) || ! skip_chars(fp, opener) ) { g_error("Cannot get item text"); return FALSE; } y = 0; while(y < x) { if ( (c = fgetc(fp)) == EOF) { g_error("Short item text"); return FALSE; } buf[y++] = (char)c; } buf[y] = '\0'; g_print("Text = %s\n", buf); return TRUE; } if (strcmp(keyword, "Dates") == 0) { if ( ! getid(fp, buf)) { g_error("Cannot get date"); return FALSE; } return get_dates(fp, buf,ptr); } if (strcmp(keyword, "Deleted") == 0) { if (! skip_whitespace(fp) || ! get_number(fp, &x)) { g_error("Cannot get deleted day"); return FALSE; } g_print("%d/", x); if (! skip_whitespace(fp) || ! get_number(fp, &x)) { g_error("Cannot get deleted month"); return FALSE; } g_print("%d/", x); if (! skip_whitespace(fp) || ! get_number(fp, &x)) { g_error("Cannot get deleted year"); return FALSE; } g_print("%d\n", x); return TRUE; } if (strcmp(keyword, "Hilite") == 0) { if (! get_string(fp, buf) ) { g_error("Cannot get hilite data"); return FALSE; } g_print("Hilite = %s\n", buf); return TRUE; } if (strcmp(keyword, "Todo") == 0) { g_print("Todo\n"); return TRUE; } if (strcmp(keyword, "Done") == 0) { g_print("Done\n"); return TRUE; } return FALSE; } void parse_ical_file(char const *file) { FILE *fp; int finished; char keyword[50]; int file_major, file_minor; char c; int item_type; int incomplete_item; struct event *myevent; if ( (fp = fopen(file, "r")) == NULL) { g_error("couldn't open file"); return; } finished = FALSE; if (!skip_whitespace(fp)) return; if (! skip_chars(fp, "Calendar") || ! skip_whitespace(fp) ) { g_error("unable to find calendar file"); fclose(fp); return; } if (! skip_chars(fp, opener) || ! skip_chars(fp, "v") ) { g_error("Unable to get version line"); fclose(fp); return; } if (! get_number(fp, &file_major) || ! (file_major >=0) || (file_major > VersionMajor)) { g_error("Missing/bad major version"); fclose(fp); return; } if (! skip_chars(fp, ".") || ! get_number(fp, &file_minor) || ! skip_chars(fp, "]") || ! skip_whitespace(fp) ) { g_error("Missing minor version"); fclose(fp); return; } if (file_minor > 0) { g_error("Bad minor version"); fclose(fp); return; } while(TRUE) { g_print("----------------------------------------\n"); item_type= 0; skip_whitespace(fp); if (! getid(fp,keyword) || ! skip_whitespace(fp) || ! skip_chars(fp, opener) || ! skip_whitespace(fp) ) { fclose(fp); return; } if (strcmp(keyword, "Appt") == 0) { g_print("New Appointment\n"); item_type = 1; } else if (strcmp(keyword, "Note") == 0) { g_print("New Note\n"); item_type = 2; } else g_print("New ??? (%s)\n", keyword); incomplete_item = TRUE; myevent = g_malloc0(sizeof(struct event)); while(incomplete_item) { if (! skip_whitespace(fp) || ! peek_char(fp, &c)) { g_warning("Incomplete item\n"); fclose(fp); return; } if (c == closer[0]) { (void)fgetc(fp); g_print("done!\n"); incomplete_item = FALSE; g_slist_append(eventlist, myevent); break; } if (! getid(fp,keyword) || ! skip_whitespace(fp) || ! skip_chars(fp, opener) ) { g_error("Error reading item property name"); fclose(fp); return; } if ( ! parse_item(fp, myevent, keyword) && ! parse_appointment(fp, myevent, keyword) ) { g_warning("Unable to parse line\n"); fclose(fp); return; } if ( ! skip_whitespace(fp) || ! skip_chars(fp, closer)) { g_error("Error reading item property"); fclose(fp); return; } } /* while */ } /* while */ } int main(int argc, char *argv[]) { eventlist = g_slist_alloc(); parse_ical_file("/home/csmall/.calendar"); g_slist_foreach(eventlist, print_glist, NULL); return 0; }