aboutsummaryrefslogblamecommitdiffstats
path: root/calendar/lexer.c
blob: e03cb666fbe7d40582f2c55d80abdeccaa98f772 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12




                                        
                       





                      













                                                                                                                                                                                                        











































                                                    

                                      
                                    
                 


                               
                    























                                       
                                         
















                                            


























                                                                                  

















                                                
                                                                  








                                                                      
                                                                          
                                    








                                                                      
                                                    
























                                                                  
                                                            




































                                                                           
                                             






















                                                                                    
                                        


                                                   
                                              




















































                                                                    
                              




























































                                                                                                 
                                                          









                                                                           
                                                                   








                                                                            
                                                                                                                


















                                                                                 
                                    
                                                  
                                                      


                 
/*
 * lexer.c: Reads in the .calendar files
 */
#include <stdio.h>
#include <glib.h>
#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;
}