first commit
This commit is contained in:
199
calmodule.c
Normal file
199
calmodule.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/* calmodule.c
|
||||
* Author: Bronson Graansma 0872249
|
||||
* Contact: bgraansm@mail.uoguelph.ca
|
||||
* Date: March 17, 2016
|
||||
* Description: python - c extension for xcal */
|
||||
|
||||
#include <Python.h>
|
||||
#include "calutil.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static char* parseError(char* file, CalStatus status) {
|
||||
char* err = "UNKNOWN";
|
||||
char* out = NULL;
|
||||
|
||||
switch(status.code) {
|
||||
case OK : err = "OK"; break;
|
||||
case AFTEND: err = "AFTEND"; break;
|
||||
case BADVER: err = "BADVER"; break;
|
||||
case BEGEND: err = "BEGEND"; break;
|
||||
case IOERR : err = "IOERR"; break;
|
||||
case NOCAL : err = "NOCAL"; break;
|
||||
case NOCRNL: err = "NOCRNL"; break;
|
||||
case NODATA: err = "NODATA"; break;
|
||||
case NOPROD: err = "NOPROD"; break;
|
||||
case SUBCOM: err = "SUBCOM"; break;
|
||||
case SYNTAX: err = "SYNTAX"; break;
|
||||
}
|
||||
|
||||
out = malloc(strlen(err) + strlen(file) + 30);
|
||||
sprintf(out, "%s: %s in lines %d-%d\n",
|
||||
file, err, status.linefrom, status.lineto);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static char* formatTime(char* str) {
|
||||
//'YYYY-MM-DD HH:MM:SS'
|
||||
char* format = malloc(20);
|
||||
|
||||
assert(format != NULL);
|
||||
if(str == NULL || strlen(str) < 15) {
|
||||
free(format);
|
||||
return "0000-00-00 00:00:00";
|
||||
}
|
||||
|
||||
for(int i = 0; i < 19; i++) {
|
||||
format[i] = ' ';
|
||||
}
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
format[i] = str[i];
|
||||
}
|
||||
|
||||
for(int i = 0; i < 2; i++) {
|
||||
format[i + 5] = str[i + 4];
|
||||
format[i + 8] = str[i + 6];
|
||||
format[i + 11] = str[i + 9];
|
||||
format[i + 14] = str[i + 11];
|
||||
format[i + 17] = str[i + 13];
|
||||
}
|
||||
format[4] = '-';
|
||||
format[7] = '-';
|
||||
format[13] = ':';
|
||||
format[16] = ':';
|
||||
format[19] = '\0';
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
static PyObject *Cal_readFile( PyObject *self, PyObject *args ) {
|
||||
CalStatus status = initCalStatus(OK, 0,0);
|
||||
char *filename = NULL;
|
||||
PyObject *result = PyTuple_New(2);
|
||||
PyObject *tuple = NULL;
|
||||
FILE* ics = NULL;
|
||||
CalComp* pcal = NULL;
|
||||
|
||||
PyArg_ParseTuple(args, "s", &filename);
|
||||
ics = fopen(filename, "r");
|
||||
|
||||
if(ics == NULL) {
|
||||
PyTuple_SetItem(result, 0, Py_BuildValue("s", "error"));
|
||||
PyTuple_SetItem(result, 1, Py_BuildValue("s", strerror(errno)));
|
||||
return result;
|
||||
} else {
|
||||
status = readCalFile(ics, &pcal);
|
||||
}
|
||||
fclose(ics);
|
||||
|
||||
if(status.code != OK) {
|
||||
char* out = parseError(filename, status);
|
||||
PyTuple_SetItem(result, 0, Py_BuildValue("s", "error"));
|
||||
PyTuple_SetItem(result, 1, Py_BuildValue("s", out));
|
||||
free(out);
|
||||
return result;
|
||||
}
|
||||
tuple = PyTuple_New(pcal->ncomps);
|
||||
|
||||
for(int i = 0; i < pcal->ncomps; i++) {
|
||||
char* summary = " ";
|
||||
char* orgName = " ";
|
||||
char* orgInfo = " ";
|
||||
char* locaton = " ";
|
||||
char* priorty = " ";
|
||||
char* dtstart = "0000-00-00 00:00:00";
|
||||
CalProp* prop = pcal->comp[i]->prop;
|
||||
PyObject *tmp = NULL;
|
||||
|
||||
for(int j = 0; j < pcal->comp[i]->nprops; j++) {
|
||||
if(strcmp(prop->name, "ORGANIZER") == 0) {
|
||||
CalParam* param = prop->param;
|
||||
for(int k = 0; k < prop->nparams; k++) {
|
||||
if(strcmp(param->name, "CN") == 0) {
|
||||
orgName = param->value[0];
|
||||
break;
|
||||
}
|
||||
param = param->next;
|
||||
}
|
||||
orgInfo = prop->value;
|
||||
} else if(strcmp(prop->name, "DTSTART") == 0) {
|
||||
dtstart = formatTime(prop->value);
|
||||
} else if(strcmp(prop->name, "LOCATION") == 0) {
|
||||
locaton = prop->value;
|
||||
} else if(strcmp(prop->name, "PRIORITY") == 0) {
|
||||
priorty = prop->value;
|
||||
} else if(strcmp(prop->name, "SUMMARY") == 0) {
|
||||
summary = prop->value;
|
||||
}
|
||||
prop = prop->next;
|
||||
}
|
||||
|
||||
tmp = Py_BuildValue("(s,i,i,s,s,s,s,s,s)",pcal->comp[i]->name,
|
||||
pcal->comp[i]->nprops, pcal->comp[i]->ncomps, summary,
|
||||
orgName, orgInfo, dtstart, locaton, priorty);
|
||||
PyTuple_SetItem(tuple, i, tmp);
|
||||
|
||||
if(strcmp(dtstart, "0000-00-00 00:00:00") != 0) {
|
||||
free(dtstart);
|
||||
}
|
||||
}
|
||||
PyTuple_SetItem(result, 0, Py_BuildValue("k", (unsigned long*)pcal));
|
||||
PyTuple_SetItem(result, 1, tuple);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *Cal_writeFile(PyObject *self, PyObject *args ) {
|
||||
CalStatus status = initCalStatus(OK, 0, 0);
|
||||
char *filename = NULL;
|
||||
CalComp *pcal = NULL;
|
||||
FILE* ics = NULL;
|
||||
int compNum = 0;
|
||||
|
||||
PyArg_ParseTuple(args, "ski", &filename, (unsigned long*)&pcal, &compNum);
|
||||
|
||||
ics = fopen(filename, "w");
|
||||
|
||||
if(ics == NULL) {
|
||||
return Py_BuildValue("s", strerror(errno));
|
||||
} else if(compNum > -1) {
|
||||
status = writeCalComp(ics, pcal->comp[compNum]);
|
||||
} else {
|
||||
status = writeCalComp(ics, pcal);
|
||||
}
|
||||
fclose(ics);
|
||||
|
||||
if(status.code != OK) {
|
||||
char* out = parseError(filename, status);
|
||||
PyObject* pOut = Py_BuildValue("s", out);
|
||||
free(out);
|
||||
return pOut;
|
||||
}
|
||||
|
||||
return Py_BuildValue("s", "OK");
|
||||
}
|
||||
|
||||
static PyObject *Cal_freeFile( PyObject *self, PyObject *args ) {
|
||||
CalComp *pcal;
|
||||
|
||||
PyArg_ParseTuple(args, "k", (unsigned long*)&pcal);
|
||||
|
||||
freeCalComp(pcal);
|
||||
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
|
||||
static PyMethodDef CalMethods[] = {
|
||||
{"readFile", Cal_readFile, METH_VARARGS},
|
||||
{"writeFile", Cal_writeFile, METH_VARARGS},
|
||||
{"freeFile", Cal_freeFile, METH_VARARGS},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static struct PyModuleDef calModuleDef = {PyModuleDef_HEAD_INIT, "Cal", NULL, -1, CalMethods};
|
||||
|
||||
PyMODINIT_FUNC PyInit_Cal(void) {
|
||||
return PyModule_Create(&calModuleDef);
|
||||
}
|
||||
39
caltool.h
Normal file
39
caltool.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* caltool.h
|
||||
* Author: Bronson Graansma 0872249
|
||||
* Contact: bgraansm@mail.uoguelph.ca
|
||||
* Date: Feb 21, 2016
|
||||
* Description: Public Interface for caltool. */
|
||||
|
||||
#ifndef CALTOOL_H
|
||||
#define CALTOOL_H A2_RevA
|
||||
|
||||
#define _GNU_SOURCE // for getdate_r
|
||||
#define _XOPEN_SOURCE // for strptime
|
||||
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include "calutil.h"
|
||||
|
||||
/* Symbols used to send options to command execution modules */
|
||||
|
||||
typedef enum {
|
||||
OEVENT, // events
|
||||
OPROP, // properties
|
||||
OTODO, // to-do items
|
||||
} CalOpt;
|
||||
|
||||
/* iCalendar tool functions */
|
||||
|
||||
CalStatus calInfo( const CalComp *comp, int lines, FILE *const txtfile );
|
||||
CalStatus calExtract( const CalComp *comp, CalOpt kind, FILE *const txtfile );
|
||||
CalStatus calFilter( const CalComp *comp, CalOpt content, time_t datefrom,
|
||||
time_t dateto, FILE *const icsfile );
|
||||
CalStatus calCombine( const CalComp *comp1, const CalComp *comp2,
|
||||
FILE *const icsfile );
|
||||
|
||||
#endif
|
||||
987
calutil.c
Normal file
987
calutil.c
Normal file
@@ -0,0 +1,987 @@
|
||||
/* calutil.c
|
||||
* Author: Bronson Graansma 0872249
|
||||
* Contact: bgraansm@mail.uoguelph.ca
|
||||
* Date: Feb 21, 2016
|
||||
* Description: Reads in an ics file and stores meaningful info in memory.
|
||||
* Various status codes are provided in order to discern what
|
||||
* went wrong in the file while reading it. */
|
||||
|
||||
#include "calutil.h"
|
||||
|
||||
#define BUFF_LEN 1024
|
||||
|
||||
/* Function name: initCalStatus
|
||||
* Description: Initialize a CalStatus' members.
|
||||
* Args: Code and lines to initilaize your CalStatus with.
|
||||
* Returns: A CalStatus with values you passed. */
|
||||
CalStatus initCalStatus(CalError code, int linefrom, int lineto) {
|
||||
CalStatus status;
|
||||
|
||||
status.code = code;
|
||||
status.linefrom = linefrom;
|
||||
status.lineto = lineto;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Function name: initCalProp
|
||||
* Description: Initialize a CalProp's members.
|
||||
* Returns: A CalProp with nul or 0 values. */
|
||||
static CalProp initCalProp(void) {
|
||||
CalProp prop;
|
||||
|
||||
prop.name = NULL;
|
||||
prop.value = NULL;
|
||||
prop.nparams = 0;
|
||||
prop.param = NULL;
|
||||
prop.next = NULL;
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
/* Function name: initCalComp
|
||||
* Description: Initialize a CalComp's members to nul or 0
|
||||
* Args: The adress of the CalComp to initialize. */
|
||||
static void initCalComp(CalComp* comp) {
|
||||
comp->name = NULL;
|
||||
comp->prop = NULL;
|
||||
comp->ncomps = 0;
|
||||
comp->nprops = 0;
|
||||
}
|
||||
|
||||
/* Function name: printBuffer
|
||||
* Description: Prints a string to a file, and folds any strings that
|
||||
* are longer than FOLD_LEN bytes.
|
||||
* Args: The char* to print, and the stream to print it to.
|
||||
* Returns: The number of lines written, or it's negative if an error. */
|
||||
static int printBuffer(char* buff, FILE* ics) {
|
||||
int len = strlen(buff);
|
||||
int lines = 0;
|
||||
int count = 0;
|
||||
|
||||
for(int i = 0; i < len; i++) {
|
||||
if(fprintf(ics, "%c", buff[i]) < 0) {
|
||||
return lines * (-1);
|
||||
}
|
||||
count++;
|
||||
if(i == len - 1) {
|
||||
if(fprintf(ics, "\r\n") < 0) {
|
||||
return lines * (-1);
|
||||
}
|
||||
lines++;
|
||||
break;
|
||||
}
|
||||
if(count == FOLD_LEN) {
|
||||
if(fprintf(ics, "\r\n ") < 0) {
|
||||
return lines * (-1);
|
||||
}
|
||||
lines++;
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/* Function name: printParam
|
||||
* Description: Formats a string to match iCalandar syntax for parameters.
|
||||
* Args: The parameter to format a string for, and the string to store it in.*/
|
||||
static void printParam(CalParam* param, char** buff) {
|
||||
char* comma = "";
|
||||
char* temp = NULL;
|
||||
|
||||
if(param == NULL) {
|
||||
return;
|
||||
} else if(*buff == NULL) {
|
||||
*buff = malloc(1);
|
||||
(*buff)[0] = '\0';
|
||||
assert(*buff != NULL);
|
||||
}
|
||||
|
||||
*buff = realloc(*buff, strlen(*buff) + strlen(param->name) + 3);
|
||||
assert(*buff != NULL);
|
||||
temp = malloc(strlen(*buff) + strlen(param->name) + 3);
|
||||
assert(temp != NULL);
|
||||
|
||||
sprintf(temp, "%s;%s=", *buff, param->name);
|
||||
sprintf(*buff, "%s", temp);
|
||||
|
||||
for(int i = 0; i < param->nvalues; i++) {
|
||||
*buff = realloc(*buff, strlen(*buff) + strlen(param->value[i]) + 2);
|
||||
temp = realloc(temp , strlen(temp ) + strlen(param->value[i]) + 2);
|
||||
assert(*buff != NULL && temp != NULL);
|
||||
sprintf(temp, "%s", *buff);
|
||||
sprintf(*buff, "%s%s%s", temp, comma, param->value[i]);;
|
||||
comma = ",";
|
||||
}
|
||||
free(temp);
|
||||
printParam(param->next, buff);
|
||||
}
|
||||
|
||||
/* Function name: printProp
|
||||
* Description: Recursively prints a property to a stream in iCalandar syntax.
|
||||
* Args: The property to print, and the stream to print it to.
|
||||
* Returns: The number of lines written, or it's negative if an error. */
|
||||
static int printProp(CalProp* prop, FILE* ics) {
|
||||
char* buff = NULL;
|
||||
char* temp = NULL;
|
||||
int lines = 0;
|
||||
int ioerr = 0;
|
||||
int len = 0;
|
||||
|
||||
if(prop == NULL) {
|
||||
return 0;
|
||||
} else if(prop->name == NULL) {
|
||||
len = 0;
|
||||
} else {
|
||||
len = strlen(prop->name);
|
||||
}
|
||||
|
||||
buff = malloc(len + 1);
|
||||
assert(buff != NULL);
|
||||
|
||||
sprintf(buff, "%s", prop->name);
|
||||
printParam(prop->param, &buff);
|
||||
temp = malloc(strlen(buff) + strlen(prop->value) + 4);
|
||||
assert(temp != NULL);
|
||||
sprintf(temp, "%s:%s", buff, prop->value);
|
||||
free(buff);
|
||||
lines = printBuffer(temp, ics);
|
||||
free(temp);
|
||||
|
||||
if(lines < 0) {
|
||||
return lines;
|
||||
}
|
||||
|
||||
ioerr = printProp(prop->next, ics);
|
||||
if(ioerr < 0) {
|
||||
return ((-1) * lines) + ioerr;
|
||||
}
|
||||
|
||||
return lines + ioerr;
|
||||
}
|
||||
|
||||
/* Function name: printComp
|
||||
* Description: Recursively prints a component to a stream in iCalandar syntax.
|
||||
* Args: The component to print, and the stream to print it to.
|
||||
* Returns: The number of lines written, or it's negative if an error. */
|
||||
static int printComp(const CalComp* comp, FILE* ics) {
|
||||
int lines = 0;
|
||||
int ioerr = 0;
|
||||
char* buff = NULL;
|
||||
|
||||
if(comp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
buff = malloc(strlen(comp->name) + 9);
|
||||
assert(buff != NULL);
|
||||
|
||||
sprintf(buff, "BEGIN:%s", comp->name);
|
||||
lines = printBuffer(buff, ics);
|
||||
free(buff);
|
||||
if(lines < 0) {
|
||||
return lines;
|
||||
}
|
||||
buff = NULL;
|
||||
ioerr = printProp(comp->prop, ics);
|
||||
if(ioerr < 0) {
|
||||
return ((-1) * lines) + ioerr;
|
||||
}
|
||||
lines += ioerr;
|
||||
|
||||
for(int i = 0; i < comp->ncomps; i++) {
|
||||
ioerr = printComp(comp->comp[i], ics);
|
||||
if(ioerr < 0) {
|
||||
return ((-1) * lines) + ioerr;
|
||||
}
|
||||
lines += ioerr;
|
||||
}
|
||||
buff = malloc(strlen(comp->name) + 7);
|
||||
assert(buff != NULL);
|
||||
sprintf(buff, "END:%s", comp->name);
|
||||
ioerr = printBuffer(buff, ics);
|
||||
free(buff);
|
||||
|
||||
if(ioerr < 0) {
|
||||
return ((-1) * lines) + ioerr;
|
||||
}
|
||||
return lines + ioerr;
|
||||
}
|
||||
|
||||
/* Function name: validateProp
|
||||
* Description: Validates that there is only 1 version, and that it matches
|
||||
* VCAL_VER macro. Also validates that there is only 1 prodid.
|
||||
* Note: To reset static variables safely, call with (NULL, true).
|
||||
* Args: The CalProp to validate
|
||||
* Returns: The error code if any, OK otherwise. */
|
||||
static CalError validateProp(CalComp* comp) {
|
||||
int nprodid = 0;
|
||||
int nversion = 0;
|
||||
|
||||
for(CalProp* prop = comp->prop; prop != NULL; prop = prop->next) {
|
||||
if(strcmp(prop->name, "VERSION") == 0) {
|
||||
nversion++;
|
||||
if(strcmp(prop->value, VCAL_VER) != 0) {
|
||||
return BADVER;
|
||||
}
|
||||
} else if (strcmp(prop->name, "PRODID") == 0) {
|
||||
nprodid++;
|
||||
}
|
||||
}
|
||||
|
||||
if(nversion != 1) {
|
||||
return BADVER;
|
||||
} else if(nprodid != 1) {
|
||||
return NOPROD;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Function name: validateComp
|
||||
* Description: Validates that at least one component starts with V,
|
||||
* and that there is atleast one component.
|
||||
* Args: The CalComp to validate.
|
||||
* Returns: The error code if any, OK otherwise. */
|
||||
static CalError validateComp(CalComp* comp) {
|
||||
int vCount = 0; /* must have at least one comp stating with "V" */
|
||||
|
||||
for(int i = 0; i < comp->ncomps; i++) {
|
||||
if((comp->comp[i])->name[0] == 'V') {
|
||||
vCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if(comp->ncomps == 0 || vCount == 0) {
|
||||
return NOCAL;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Function name: displace
|
||||
* Description: Moves each character in a string forward by the amount of
|
||||
* characters specified.
|
||||
* Args: String to displace, and the number of characters to offset it by. */
|
||||
static void displace(char* str, int offset) {
|
||||
int len = strlen(str);
|
||||
|
||||
for(int i = 0; i < len - offset; i++) {
|
||||
str[i] = str[i + offset];
|
||||
}
|
||||
str[len - offset] = '\0';
|
||||
}
|
||||
|
||||
/* Function name: removeCRNL
|
||||
* Description: Checks for \r\n sequence and removes it.
|
||||
* Args: The string to search for CRNL.
|
||||
* Returns: True if CRNL was found and removed, false otherwise. */
|
||||
static bool removeCRNL(char* str) {
|
||||
int len = strlen(str);
|
||||
|
||||
for(int i = 0; i < len; i++) {
|
||||
switch(str[i]) {
|
||||
case '\r':
|
||||
str[i] = '\0';
|
||||
return str[i + 1] == '\n';
|
||||
case '\n':
|
||||
str[i] = '\0';
|
||||
return str[i - 1] == '\r';
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Function name: isEmpty
|
||||
* Description: Checks if a string contains only whitespace.
|
||||
* Args: The string to check.
|
||||
* Returns: True if string is all whitespace, false otherwise. */
|
||||
static bool isEmpty(char* str) {
|
||||
int len = strlen(str);
|
||||
|
||||
for(int i = 0; i < len; i++) {
|
||||
if(isspace(str[i]) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Function name: removeLead
|
||||
* Description: Checks for and removes a leading whitespace character.
|
||||
* Args: The string to check for and remove leading whitespace from.
|
||||
* Returns: True if string began with whitespace, false otherwise. */
|
||||
static bool removeLead(char* str) {
|
||||
int len = strlen(str);
|
||||
int i = 0;
|
||||
|
||||
if(str[0] == ' ' || str[0] == '\t') {
|
||||
for(i = 0; i < len - 1; i++) {
|
||||
if(str[i] == '\0') {
|
||||
break;
|
||||
}
|
||||
str[i] = str[i + 1];
|
||||
}
|
||||
str[i] = '\0';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Function name: capitalize
|
||||
* Description: Converts a string to uppercase.
|
||||
* Args: The string to make uppercase. */
|
||||
static void capitalize(char* str) {
|
||||
int len = strlen(str);
|
||||
|
||||
for(int i = 0; i < len; i++) {
|
||||
str[i] = toupper(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Function name: checkStart
|
||||
* Description: Determines if a prop matches "BEGIN:VCALENDAR".
|
||||
* Args: The prop to check.
|
||||
* Returns: True if prop matches "BEGIN:VCALENDAR", false otherwise. */
|
||||
static bool checkStart(CalProp prop) {
|
||||
bool check = false;
|
||||
|
||||
if(prop.name == NULL || prop.value == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
capitalize(prop.value);
|
||||
|
||||
check = strcmp(prop.name, "BEGIN") == 0;
|
||||
check = check && strcmp(prop.value, "VCALENDAR") == 0;
|
||||
check = check && prop.nparams == 0;
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
/* Function name: parseName
|
||||
* Description: Identifies the name in this string and stores it in prop->name.
|
||||
* Also removes the name from the string to simplify future parse.
|
||||
* Args: The string to parse a name out of, and the prop to store it in.
|
||||
* Returns: True if a name was found, false otherwise. */
|
||||
static bool parseName(char* str, CalProp* prop) {
|
||||
int offset = 0;
|
||||
int len = strlen(str);
|
||||
bool success = false;
|
||||
int i = 0;
|
||||
|
||||
if(str == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(i = 0; i < len + 1; i++) {
|
||||
if(str[i] == ';' || str[i] == ':') { /* property name ends here */
|
||||
if(i == 0) {
|
||||
return false;
|
||||
}
|
||||
offset = i;
|
||||
success = true;
|
||||
break;
|
||||
} else if(str[i] == '\0' || str[i] == '\"' || isspace(str[i])) {
|
||||
free(prop->name); /* property doesn't have a value, or it has */
|
||||
prop->name = NULL; /* quotes or whitespace in it */
|
||||
return false;
|
||||
}
|
||||
|
||||
prop->name = realloc(prop->name, i + 2);
|
||||
assert(prop->name != NULL);
|
||||
prop->name[i] = str[i];
|
||||
}
|
||||
prop->name[i] = '\0';
|
||||
|
||||
displace(str, offset);
|
||||
capitalize(prop->name);
|
||||
|
||||
if(strlen(prop->name) == 0) {
|
||||
free(prop->name);
|
||||
prop->name = NULL;
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/* Function name: parseParam
|
||||
* Description: Identifies the parameters in this string, and stores them in
|
||||
* prop->param linked list, and increments prop->nparams for each.
|
||||
* Also removes the params from string to simplify future parse.
|
||||
* Args: The string to parse patameters out of, and the prop to store them in.
|
||||
* Note: If a parameter contains a syntax error, str will be damaged in order
|
||||
* for parseValue to throw the SYNTAX error.
|
||||
* Returns: True if any parameters were found, false otherwise. */
|
||||
static bool parseParam(char* str, CalProp* prop) {
|
||||
int len = strlen(str);
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int vals = 0;
|
||||
int offset = 0;
|
||||
CalParam* param = prop->param;
|
||||
bool quoted = false;
|
||||
char name [len + 1];
|
||||
char value[len + 1];
|
||||
char temp [len + 1];
|
||||
|
||||
if(str == NULL || str[0] != ';' || len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(i = 1; i < len; i++) { /* parse parameter name out */
|
||||
if(str[i] == ':' || str[i] == ';') {
|
||||
offset = i; /* parameter name ends here if no value */
|
||||
break;
|
||||
} else if(str[i] == '\"' || str[i] == ' ' || str[i] == '\t') {
|
||||
str[i] = '\"';
|
||||
str[0] = '\0';
|
||||
return false;
|
||||
} else if(quoted == false && str[i] == '=') {
|
||||
vals = 1;
|
||||
offset = i + 1;
|
||||
break; /* parameter name ends here */
|
||||
}
|
||||
|
||||
name[i - 1] = str[i];
|
||||
}
|
||||
name[i - 1] = '\0';
|
||||
|
||||
if(vals != 1) { /* param wasn't proper */
|
||||
str[i] = '\"';
|
||||
str[0] = '\0';
|
||||
return false; /* return while buffer is wrecked, so future parsing */
|
||||
} /* returns a SYNTAX error */
|
||||
|
||||
capitalize(name);
|
||||
displace(str, offset);
|
||||
|
||||
if(strlen(name) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
len = strlen(str);
|
||||
offset = 0;
|
||||
|
||||
for(i = 0; i < len; i++) { /* parse parameter value out */
|
||||
if(quoted == false && (str[i] == ':' || str[i] == ';')) {
|
||||
offset = i; /* parameter value ends here */
|
||||
break;
|
||||
} else if(quoted == false && isspace(str[i]) == true) {
|
||||
str[i] = '\"';
|
||||
str[0] = '\0';
|
||||
return false;
|
||||
}else if(str[i] == '\"') {
|
||||
quoted = !quoted;
|
||||
} else if(quoted == false && str[i] == ',') {
|
||||
vals++; /* this parameter has multiple values */
|
||||
}
|
||||
|
||||
value[i] = str[i];
|
||||
}
|
||||
value[i] = '\0';
|
||||
|
||||
displace(str, offset);
|
||||
|
||||
for(param = prop->param; param != NULL; param = param->next) {
|
||||
if(param->next == NULL) { /* find the end of linked list */
|
||||
break; /* parameters will be copied into the end of list */
|
||||
}
|
||||
}
|
||||
|
||||
if(prop->nparams == 0) { /* this is first parameter */
|
||||
prop->param = malloc(sizeof(CalParam) + (vals * sizeof(char*)));
|
||||
assert(prop->param != NULL);
|
||||
param = prop->param;
|
||||
} else { /* copy into the end of the linked list */
|
||||
param->next = malloc(sizeof(CalParam) + (vals * sizeof(char*)));
|
||||
assert(param->next != NULL);
|
||||
param = param->next;
|
||||
}
|
||||
prop->nparams++;
|
||||
param->nvalues = vals;
|
||||
param->next = NULL;
|
||||
|
||||
param->name = malloc(strlen(name) + 1);
|
||||
assert(param->name != NULL);
|
||||
strncpy(param->name, name, strlen(name));
|
||||
param->name[strlen(name)] = '\0';
|
||||
|
||||
for(i = 0; i < vals; i++) { /* seperate the values */
|
||||
offset = 0;
|
||||
len = strlen(value);
|
||||
|
||||
for(j = 0; j < len; j++) {
|
||||
if(value[j] == '\"') {
|
||||
quoted = !quoted;
|
||||
} else if(quoted == false && value[j] == ',') {
|
||||
offset = j + 1; /* a value ends here */
|
||||
break;
|
||||
} else if(j == len - 1) {
|
||||
offset = j; /* the last value ends here */
|
||||
}
|
||||
temp[j] = value[j];
|
||||
}
|
||||
temp[j] = '\0';
|
||||
|
||||
displace(value, offset);
|
||||
|
||||
param->value[i] = malloc(strlen(temp) + 1);
|
||||
assert(param->value[i] != NULL);
|
||||
strncpy(param->value[i], temp, strlen(temp));
|
||||
(param->value[i])[strlen(temp)] = '\0';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Function name: parseValue
|
||||
* Description: Identifies the value in this string and stores it in prop.
|
||||
* Args: The string to parse the value out of, and the prop to store it in.
|
||||
* Returns: True if the value was found, false otherwise. */
|
||||
static bool parseValue(char* str, CalProp* prop) {
|
||||
int len = strlen(str);
|
||||
|
||||
if(str == NULL || str[0] != ':' || strlen(str) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
prop->value = malloc(len);
|
||||
assert(prop->value != NULL);
|
||||
|
||||
for(int i = 0; i < len; i++) { /* copy the string without the colon ':' */
|
||||
prop->value[i] = str[i + 1]; /* includes null terminator */
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Function name: freeCalParam
|
||||
* Description: Recursively frees allocated CalParams in this linked list.
|
||||
* Args: The head of the linked list of CalParams to free. */
|
||||
static void freeCalParam(CalParam* param) {
|
||||
if(param == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(param->name);
|
||||
param->name = NULL;
|
||||
|
||||
freeCalParam(param->next);
|
||||
free(param->next);
|
||||
param->next = NULL;
|
||||
|
||||
for(int i = 0; i < param->nvalues; i++) {
|
||||
free(param->value[i]);
|
||||
param->value[i] = NULL;
|
||||
}
|
||||
param->nvalues = 0;
|
||||
}
|
||||
|
||||
/* Function name: freeCalProp
|
||||
* Description: Recursively frees allocated CalProp in this linked list.
|
||||
* Args: The head of the linked list of CalProps to free. */
|
||||
static void freeCalProp(CalProp* prop) {
|
||||
if(prop == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(prop->name);
|
||||
prop->name = NULL;
|
||||
|
||||
free(prop->value);
|
||||
prop->value = NULL;
|
||||
|
||||
freeCalParam(prop->param);
|
||||
free(prop->param);
|
||||
prop->param = NULL;
|
||||
|
||||
freeCalProp(prop->next);
|
||||
free(prop->next);
|
||||
prop->next = NULL;
|
||||
|
||||
prop->nparams = 0;
|
||||
}
|
||||
|
||||
CalStatus readCalFile( FILE *const ics, CalComp **const pcomp ) {
|
||||
CalStatus status = initCalStatus(OK, 0, 0);
|
||||
char* line = NULL;
|
||||
|
||||
assert(ics != NULL && pcomp != NULL);
|
||||
|
||||
readCalLine(NULL, NULL);
|
||||
*pcomp = malloc(sizeof(CalComp));
|
||||
|
||||
assert(*pcomp != NULL);
|
||||
initCalComp(*pcomp);
|
||||
|
||||
status = readCalComp(ics, pcomp);
|
||||
|
||||
if(status.code != OK) {
|
||||
freeCalComp(*pcomp);
|
||||
*pcomp = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* file has been read successfully. performing validations below */
|
||||
|
||||
status.code = validateProp(*pcomp);
|
||||
if(status.code != OK) {
|
||||
freeCalComp(*pcomp);
|
||||
*pcomp = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
status.code = validateComp(*pcomp);
|
||||
if(status.code != OK) {
|
||||
freeCalComp(*pcomp);
|
||||
*pcomp = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
readCalLine(ics, &line);
|
||||
if(line != NULL) {
|
||||
status.code = AFTEND;
|
||||
status.linefrom++;
|
||||
status.lineto++;
|
||||
freeCalComp(*pcomp);
|
||||
*pcomp = NULL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
CalStatus readCalComp( FILE *const ics, CalComp **const pcomp ) {
|
||||
CalComp comp;
|
||||
CalStatus status = initCalStatus(OK, 0, 0);
|
||||
CalProp prop = initCalProp();
|
||||
CalProp *temp = NULL;
|
||||
char* line = NULL;
|
||||
static int depth = 0; /* keeps track of nested begins */
|
||||
static bool firstCall = true;
|
||||
const size_t size = sizeof(CalComp); /* these constants are purely for */
|
||||
const size_t sizePtr = sizeof(CalComp*); /* managing readability */
|
||||
int num = 0;
|
||||
int lineStart = 0;
|
||||
int linesRead = 0;
|
||||
|
||||
if(ics == NULL && pcomp == NULL) { /* reset static var */
|
||||
depth = 0;
|
||||
firstCall = true;
|
||||
return status;
|
||||
}
|
||||
|
||||
initCalComp(&comp);
|
||||
|
||||
do {
|
||||
free(line);
|
||||
line = NULL;
|
||||
status = readCalLine(ics, &line);
|
||||
|
||||
if(line == NULL || status.code != OK) {
|
||||
if(firstCall == true) {
|
||||
lineStart = status.linefrom + 1;
|
||||
linesRead = status.lineto + 1;
|
||||
status = initCalStatus(NOCAL, 0, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(line == NULL && depth != 0) {
|
||||
status.code = BEGEND;
|
||||
break;
|
||||
}
|
||||
|
||||
status.code = parseCalProp(line, &prop);
|
||||
if(status.code != OK) {
|
||||
freeCalProp(&prop);
|
||||
break;
|
||||
}
|
||||
|
||||
if((*pcomp)->name == NULL && checkStart(prop) == false) {
|
||||
status.code = NOCAL; /* first component isnt BEGIN:VCALENDAR */
|
||||
freeCalProp(&prop);
|
||||
break;
|
||||
} else if((*pcomp)->name == NULL) { /* create the first compnent */
|
||||
(*pcomp)->name = malloc(strlen(prop.value) + 1);
|
||||
assert((*pcomp)->name != NULL);
|
||||
strncpy((*pcomp)->name, prop.value, strlen(prop.value));
|
||||
(*pcomp)->name[strlen(prop.value)] = '\0';
|
||||
|
||||
depth = 1;
|
||||
freeCalProp(&prop);
|
||||
prop = initCalProp();
|
||||
continue;
|
||||
}
|
||||
|
||||
if(strcmp(prop.name, "BEGIN") == 0) {
|
||||
capitalize(prop.value);
|
||||
if(depth >= 3) {
|
||||
status.code = SUBCOM;
|
||||
freeCalProp(&prop);
|
||||
break;
|
||||
} else { /* create a new compnent with values from prop */
|
||||
comp.name = malloc(strlen(prop.value) + 1);
|
||||
assert(comp.name != NULL);
|
||||
|
||||
strncpy(comp.name, prop.value, strlen(prop.value));
|
||||
comp.name[strlen(prop.value)] = '\0';
|
||||
depth++;
|
||||
|
||||
freeCalProp(&prop);
|
||||
prop = initCalProp();
|
||||
num = (*pcomp)->ncomps;
|
||||
(*pcomp)->ncomps++;
|
||||
|
||||
*pcomp = realloc(*pcomp, size + ((*pcomp)->ncomps) * sizePtr);
|
||||
(*pcomp)->comp[num] = malloc(size);
|
||||
assert((*pcomp != NULL) && ((*pcomp)->comp[num] != NULL));
|
||||
|
||||
*((*pcomp)->comp[num]) = comp;
|
||||
/* put newly created comp into the flexible array member */
|
||||
|
||||
status = readCalComp(ics, &((*pcomp)->comp[num]));
|
||||
/* read the next compnents into the new one */
|
||||
if(status.code != OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if(strcmp(prop.name, "END") == 0) {
|
||||
capitalize(prop.value);
|
||||
if((*pcomp)->ncomps == 0 && (*pcomp)->nprops == 0) {
|
||||
status.code = NODATA;
|
||||
freeCalProp(&prop);
|
||||
break;
|
||||
}
|
||||
|
||||
if(strcmp(prop.value, (*pcomp)->name) == 0) {
|
||||
if(strcmp(prop.value, "VCALENDAR") != 0) {
|
||||
depth--;
|
||||
} /* else we are done */
|
||||
freeCalProp(&prop);
|
||||
break;
|
||||
} else {
|
||||
status.code = BEGEND;
|
||||
freeCalProp(&prop);
|
||||
break;
|
||||
}
|
||||
} else { /* ordinary property */
|
||||
for(temp = (*pcomp)->prop; temp != NULL; temp = temp->next) {
|
||||
if(temp->next == NULL) {
|
||||
break; /* find place in linked list to copy to */
|
||||
}
|
||||
}
|
||||
|
||||
if(temp != NULL) { /* append to linked list */
|
||||
temp->next = malloc(sizeof(CalProp));
|
||||
assert(temp->next != NULL);
|
||||
*temp->next = prop;
|
||||
temp->next->next = NULL;
|
||||
} else { /* start a linked list */
|
||||
(*pcomp)->prop = malloc(sizeof(CalProp));
|
||||
assert((*pcomp)->prop != NULL);
|
||||
*(*pcomp)->prop = prop;
|
||||
(*pcomp)->prop->next = NULL;
|
||||
}
|
||||
|
||||
(*pcomp)->nprops++;
|
||||
prop = initCalProp();
|
||||
}
|
||||
} while(line != NULL);
|
||||
|
||||
if(status.code == NOCAL && depth != 0) {
|
||||
status = initCalStatus(BEGEND, lineStart, linesRead);
|
||||
}
|
||||
|
||||
firstCall = false;
|
||||
free(line);
|
||||
return status;
|
||||
}
|
||||
|
||||
CalStatus readCalLine( FILE *const ics, char **const pbuff ) {
|
||||
static char* readAhead = NULL; /* buffer containing content on next line */
|
||||
static int linesRead = 0; /* total number of lines read thus far */
|
||||
static bool lastLine = false; /* used to check if EOF was hit or not */
|
||||
CalError status = OK;
|
||||
char buffer[BUFF_LEN] = {'\0'};
|
||||
char temp [BUFF_LEN] = {'\0'};
|
||||
bool folded = true;
|
||||
int startLine = linesRead + 1;
|
||||
int len = 0;
|
||||
int i = 0;
|
||||
|
||||
if(ics == NULL || pbuff == NULL) { /* NULL args | prepare for a new file */
|
||||
readCalComp(NULL, NULL);
|
||||
|
||||
free(readAhead);
|
||||
readAhead = NULL;
|
||||
|
||||
linesRead = 0;
|
||||
lastLine = false;
|
||||
|
||||
return initCalStatus(OK, 0, 0);
|
||||
}
|
||||
|
||||
assert(ics != NULL && pbuff != NULL);
|
||||
|
||||
if(lastLine == true) { /* EOF was hit last call */
|
||||
*pbuff = NULL;
|
||||
return initCalStatus(status, linesRead-1, linesRead-1);
|
||||
}
|
||||
|
||||
if(readAhead == NULL && lastLine == false) { /* first call */
|
||||
if(fgets(buffer, BUFF_LEN - 1, ics) == NULL){ /* empty file */
|
||||
*pbuff = NULL;
|
||||
lastLine = true;
|
||||
return initCalStatus(OK, 0, 0);
|
||||
} else {
|
||||
linesRead++;
|
||||
}
|
||||
|
||||
if(removeCRNL(buffer) == false) {
|
||||
if(fgets(temp, BUFF_LEN - 1, ics) != NULL) {
|
||||
free(*pbuff);
|
||||
*pbuff = NULL;
|
||||
status = NOCRNL;
|
||||
folded = false;
|
||||
}
|
||||
} else {
|
||||
*pbuff = malloc(strlen(buffer) + 1);
|
||||
assert(*pbuff != NULL);
|
||||
strncpy(*pbuff, buffer, strlen(buffer));
|
||||
(*pbuff)[strlen(buffer)] = '\0';
|
||||
}
|
||||
} else { /* a string was stored last call for me */
|
||||
*pbuff = malloc(strlen(readAhead) + 1);
|
||||
assert(*pbuff != NULL);
|
||||
strncpy(*pbuff, readAhead, strlen(readAhead));
|
||||
(*pbuff)[strlen(readAhead)] = '\0';
|
||||
free(readAhead);
|
||||
readAhead = NULL;
|
||||
linesRead++;
|
||||
}
|
||||
|
||||
while(folded == true) {
|
||||
for(i = 0; i < BUFF_LEN; i++) {
|
||||
buffer[i] = '\0';
|
||||
}
|
||||
|
||||
if(fgets(buffer, BUFF_LEN - 1, ics) == NULL) {
|
||||
lastLine = true; /* let next call know not to read any further */
|
||||
folded = false; /* proccess remaining string, quit afterward */
|
||||
free(readAhead);
|
||||
readAhead = NULL;
|
||||
} else if(removeCRNL(buffer) == false) {
|
||||
if(fgets(temp, BUFF_LEN - 1, ics) != NULL) {
|
||||
free(*pbuff);
|
||||
*pbuff = NULL;
|
||||
status = NOCRNL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(isEmpty(buffer) == true) {
|
||||
linesRead++;
|
||||
}
|
||||
|
||||
folded = removeLead(buffer) && status == OK;
|
||||
|
||||
if(strlen(buffer) == 0) {
|
||||
if(*pbuff == NULL) {
|
||||
*pbuff = malloc(1);
|
||||
assert(*pbuff != NULL);
|
||||
(*pbuff)[0] = '\0';
|
||||
}
|
||||
continue;
|
||||
} else if(folded == true) { /* append buffer to the end of pbuff */
|
||||
if(*pbuff == NULL) {
|
||||
len = strlen(buffer) + 1;
|
||||
*pbuff = malloc(len);
|
||||
} else {
|
||||
len = strlen(*pbuff) + strlen(buffer) + 1;
|
||||
*pbuff = realloc(*pbuff, len);
|
||||
}
|
||||
assert(*pbuff != NULL);
|
||||
strncat(*pbuff, buffer, strlen(buffer));
|
||||
(*pbuff)[len - 1] = '\0';
|
||||
linesRead++;
|
||||
} else { /* store buffer away for use on next call */
|
||||
readAhead = malloc(strlen(buffer) + 1);
|
||||
assert(readAhead != NULL);
|
||||
strncpy(readAhead, buffer, strlen(buffer));
|
||||
readAhead[strlen(buffer)] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if(lastLine == true) {
|
||||
linesRead--;
|
||||
}
|
||||
|
||||
return initCalStatus(status, startLine, linesRead);
|
||||
}
|
||||
|
||||
CalError parseCalProp( char *const buff, CalProp *const prop ) {
|
||||
int len = strlen(buff);
|
||||
char buffer[len + 1];
|
||||
|
||||
*prop = initCalProp();
|
||||
|
||||
assert(buff != NULL && prop != NULL);
|
||||
|
||||
strncpy(buffer, buff, len);
|
||||
buffer[len] = '\0';
|
||||
|
||||
if(parseName(buffer, prop) == false) {
|
||||
freeCalProp(prop);
|
||||
*prop = initCalProp();
|
||||
return SYNTAX;
|
||||
}
|
||||
|
||||
while(parseParam(buffer, prop) == true) {
|
||||
/* optional parameters */
|
||||
}
|
||||
|
||||
if(parseValue(buffer, prop) == false) {
|
||||
freeCalProp(prop);
|
||||
*prop = initCalProp();
|
||||
return SYNTAX;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void freeCalComp( CalComp *const comp ) {
|
||||
if(comp == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(comp->name);
|
||||
comp->name = NULL;
|
||||
|
||||
freeCalProp(comp->prop);
|
||||
free(comp->prop);
|
||||
comp->prop = NULL;
|
||||
|
||||
for(int i = 0; i < comp->ncomps; i++) {
|
||||
freeCalComp(comp->comp[i]);
|
||||
comp->comp[i] = NULL;
|
||||
}
|
||||
free(comp);
|
||||
}
|
||||
|
||||
CalStatus writeCalComp( FILE *const ics, const CalComp *comp ) {
|
||||
int lines = 0;
|
||||
|
||||
if(ics == NULL || comp == NULL) {
|
||||
return initCalStatus(IOERR, 0, 0);
|
||||
}
|
||||
lines = printComp(comp, ics);
|
||||
|
||||
if(lines < 1) {
|
||||
return initCalStatus(IOERR, (-1) * lines, (-1) * lines);
|
||||
}
|
||||
return initCalStatus(OK, lines, lines);
|
||||
}
|
||||
83
calutil.h
Normal file
83
calutil.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/* caltool.h
|
||||
* Author: Bronson Graansma 0872249
|
||||
* Contact: bgraansm@mail.uoguelph.ca
|
||||
* Date: Feb 21, 2016
|
||||
* Description: Public Interface for calutil. */
|
||||
|
||||
#ifndef CALUTIL_H
|
||||
#define CALUTIL_H A2
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define FOLD_LEN 75 // fold lines longer than this length (RFC 5545 3.1)
|
||||
#define VCAL_VER "2.0" // version of standard accepted
|
||||
|
||||
|
||||
/* data structures for ICS file in memory */
|
||||
|
||||
typedef struct CalParam CalParam;
|
||||
typedef struct CalParam { // property's parameter
|
||||
char *name; // uppercase
|
||||
CalParam *next; // linked list of parameters (ends with NULL)
|
||||
int nvalues; // no. of values
|
||||
char *value[]; // uppercase or "..." (flexible array member)
|
||||
} CalParam;
|
||||
|
||||
typedef struct CalProp CalProp;
|
||||
typedef struct CalProp { // (sub)component's property (=contentline)
|
||||
char *name; // uppercase
|
||||
char *value;
|
||||
int nparams; // no. of parameters
|
||||
CalParam *param; // -> first parameter (or NULL)
|
||||
CalProp *next; // linked list of properties (ends with NULL)
|
||||
} CalProp;
|
||||
|
||||
typedef struct CalComp CalComp;
|
||||
typedef struct CalComp { // calendar's (sub)component
|
||||
char *name; // uppercase
|
||||
int nprops; // no. of properties
|
||||
CalProp *prop; // -> first property (or NULL)
|
||||
int ncomps; // no. of subcomponents
|
||||
CalComp *comp[]; // component pointers (flexible array member)
|
||||
} CalComp;
|
||||
|
||||
|
||||
/* General status return from functions */
|
||||
|
||||
typedef enum { OK=0,
|
||||
AFTEND, // more text found after end of calendar
|
||||
BADVER, // version missing or wrong
|
||||
BEGEND, // BEGIN...END not found as expected
|
||||
IOERR, // I/O error
|
||||
NOCAL, // outer block not VCALENDAR, or no V components found
|
||||
NOCRNL, // CRNL missing at end of line
|
||||
NODATA, // nothing between BEGIN...END
|
||||
NOPROD, // PRODID missing
|
||||
SUBCOM, // subcomponent not allowed
|
||||
SYNTAX, // property not in valid form0; k < prop->nparams; k++) {
|
||||
|
||||
} CalError;
|
||||
|
||||
typedef struct {
|
||||
CalError code; // error code
|
||||
int linefrom, lineto; // line numbers where error occurred
|
||||
} CalStatus;
|
||||
|
||||
|
||||
/* File I/O functions */
|
||||
|
||||
CalStatus initCalStatus(CalError code, int linefrom, int lineto);
|
||||
CalStatus readCalFile( FILE *const ics, CalComp **const pcomp );
|
||||
CalStatus readCalComp( FILE *const ics, CalComp **const pcomp );
|
||||
CalStatus readCalLine( FILE *const ics, char **const pbuff );
|
||||
CalError parseCalProp( char *const buff, CalProp *const prop );
|
||||
CalStatus writeCalComp( FILE *const ics, const CalComp *comp );
|
||||
void freeCalComp( CalComp *const comp );
|
||||
|
||||
#endif
|
||||
|
||||
7
crnl.pl
Normal file
7
crnl.pl
Normal file
@@ -0,0 +1,7 @@
|
||||
while(<>) {
|
||||
chomp($_);
|
||||
if(substr($_, length($_)-1, 1) eq "\r") {
|
||||
chomp($_);
|
||||
}
|
||||
print("$_\r\n");
|
||||
}
|
||||
28
datemsk
Normal file
28
datemsk
Normal file
@@ -0,0 +1,28 @@
|
||||
#ident "@(#)datemsk.template 1.2 99/05/10 SMI"
|
||||
%m/%d/%y %I:%M:%S %p
|
||||
%m/%d/%Y %I:%M:%S %p
|
||||
%m/%d/%y %H:%M:%S
|
||||
%m/%d/%Y %H:%M:%S
|
||||
%m/%d/%y %I:%M %p
|
||||
%m/%d/%Y %I:%M %p
|
||||
%m/%d/%y %H:%M
|
||||
%m/%d/%Y %H:%M
|
||||
%m/%d/%y
|
||||
%m/%d/%Y
|
||||
%m/%d
|
||||
%b %d, %Y %I:%M:%S %p
|
||||
%b %d, %Y %H:%M:%S
|
||||
%B %d, %Y %I:%M:%S %p
|
||||
%B %d, %Y %H:%M:%S
|
||||
%b %d, %Y %I:%M %p
|
||||
%b %d, %Y %H:%M
|
||||
%B %d, %Y %I:%M %p
|
||||
%B %d, %Y %H:%M
|
||||
%b %d, %Y
|
||||
%B %d, %Y
|
||||
%b %d
|
||||
%B %d
|
||||
%m%d%H%M%y
|
||||
%m%d%H%M%Y
|
||||
%m%d%H%M
|
||||
%m%d
|
||||
31
ics files/a.ics
Normal file
31
ics files/a.ics
Normal file
@@ -0,0 +1,31 @@
|
||||
BEGIN:VCALENDAR
|
||||
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
|
||||
VERSION:2.0
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180655Z
|
||||
DTSTAMP:20160218T180655Z
|
||||
UID:3e6715c9-d01b-4166-91cb-bf9ecfc14b45
|
||||
SUMMARY:Return library book
|
||||
PRIORITY:1
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
|
||||
erw@uoguelph.ca
|
||||
DUE;TZID=America/Toronto:20160303T140000
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:2
|
||||
X-YAHOO-YID:woofus
|
||||
X-MOZ-GENERATION:2
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180738Z
|
||||
DTSTAMP:20160218T180738Z
|
||||
UID:1a267af7-d217-4e4e-9d14-cb998af26d36
|
||||
SUMMARY:Renew magazine subscription
|
||||
PRIORITY:0
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
|
||||
erw@uoguelph.ca
|
||||
DUE;TZID=America/Toronto:20160331T170000
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:0
|
||||
X-YAHOO-YID:woofus
|
||||
END:VTODO
|
||||
END:VCALENDAR
|
||||
31
ics files/b.ics
Normal file
31
ics files/b.ics
Normal file
@@ -0,0 +1,31 @@
|
||||
BEGIN:VCALENDAR
|
||||
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
|
||||
VERSION:2.0
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180655Z
|
||||
DTSTAMP:20160218T180655Z
|
||||
UID:3e6715c9-d01b-4166-91cb-bf9ecfc14b45
|
||||
SUMMARY:Return library book
|
||||
PRIORITY:1
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
|
||||
erw@uoguelph.ca
|
||||
DUE;TZID=America/Toronto:20160303T140000
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:2
|
||||
X-YAHOO-YID:woofus
|
||||
X-MOZ-GENERATION:2
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180738Z
|
||||
DTSTAMP:20160218T180738Z
|
||||
UID:1a267af7-d217-4e4e-9d14-cb998af26d36
|
||||
SUMMARY:Renew magazine subscription
|
||||
PRIORITY:0
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
|
||||
erw@uoguelph.ca
|
||||
DUE;TZID=America/Toronto:20160331T170000
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:0
|
||||
X-YAHOO-YID:woofus
|
||||
END:VTODO
|
||||
END:VCALENDAR
|
||||
57
ics files/demo.ics
Normal file
57
ics files/demo.ics
Normal file
@@ -0,0 +1,57 @@
|
||||
BEGIN:VCALENDAR
|
||||
PRODID:demo.ics
|
||||
VERSION:2.0
|
||||
BEGIN:VTODO
|
||||
SUMMARY:Finish A4 for Angel of Death
|
||||
PRIORITY:1
|
||||
ORGANIZER;CN=William Gardner:mailto:gardnerw@uoguelph.ca
|
||||
LOCATION:Guelph
|
||||
DTSTART:20160408T235900Z
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
SUMMARY:Finish Final Project for Marketing
|
||||
PRIORITY:2
|
||||
ORGANIZER;CN=Sergio Meza:mailto:smeza@uoguelph.ca
|
||||
LOCATION:Guelph
|
||||
DTSTART:20160409T235900Z
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
SUMMARY:Do MyEconLab
|
||||
PRIORITY:3
|
||||
ORGANIZER;CN=Eveline Adomait:mailto:eadomait@uoguelph.ca
|
||||
LOCATION:Online
|
||||
DTSTART:20160410T235900Z
|
||||
END:VTODO
|
||||
BEGIN:VEVENT
|
||||
SUMMARY:Recruitment Session
|
||||
ORGANIZER;CN=Patricia Kopec:mailto:patricia@intrigueme.ca
|
||||
LOCATION:Innovation Guelph
|
||||
DTSTART:20160414T190000Z
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
SUMMARY:PKing
|
||||
ORGANIZER;CN=Bronson Graansma:mailto:bgraansm@mail.uoguelph.ca
|
||||
LOCATION:Online
|
||||
DTSTART:20160429T220000Z
|
||||
END:VEVENT
|
||||
BEGIN:VTODO
|
||||
SUMMARY:Defeat the Ender Dragon
|
||||
PRIORITY:4
|
||||
ORGANIZER;CN=Bronson Graansma:mailto:bgraansm@mail.uoguelph.ca
|
||||
LOCATION:Online
|
||||
DTSTART:20160430T220000Z
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
PRIORITY:5
|
||||
SUMMARY:Acquire Thunderfury, Blessed Blade of the Windseeker
|
||||
ORGANIZER;CN=Bronson Graansma:mailto:bgraansm@mail.uoguelph.ca
|
||||
LOCATION:Online
|
||||
DTSTART:20160503T220000Z
|
||||
END:VTODO
|
||||
BEGIN:VEVENT
|
||||
SUMMARY:New episode of Itachi-chan
|
||||
ORGANIZER;CN=Rachel Beimers:mailto:rachelbunny66@hotmail.com
|
||||
LOCATION:Woodstock
|
||||
DTSTART:20160407T063000Z
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
1878
ics files/events.ics
Normal file
1878
ics files/events.ics
Normal file
File diff suppressed because it is too large
Load Diff
234
ics files/samp1.ics
Normal file
234
ics files/samp1.ics
Normal file
@@ -0,0 +1,234 @@
|
||||
BEGIN:VCALENDAR
|
||||
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
|
||||
VERSION:2.0
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:America/Toronto
|
||||
BEGIN:DAYLIGHT
|
||||
TZOFFSETFROM:-0500
|
||||
TZOFFSETTO:-0400
|
||||
TZNAME:EDT
|
||||
DTSTART:19700308T020000
|
||||
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
|
||||
END:DAYLIGHT
|
||||
BEGIN:STANDARD
|
||||
TZOFFSETFROM:-0400
|
||||
TZOFFSETTO:-0500
|
||||
TZNAME:EST
|
||||
DTSTART:19701101T020000
|
||||
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
|
||||
END:STANDARD
|
||||
END:VTIMEZONE
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T175508Z
|
||||
LAST-MODIFIED:20160218T175549Z
|
||||
DTSTAMP:20160218T175549Z
|
||||
UID:2c8fd444-306e-416f-98ff-6af9b3a15b9b
|
||||
SUMMARY:Xmas Eve
|
||||
DTSTART;TZID=America/Toronto:20151224T183000
|
||||
DTEND;TZID=America/Toronto:20151224T220000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:Sister's house
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT30M
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T175723Z
|
||||
LAST-MODIFIED:20160218T175805Z
|
||||
DTSTAMP:20160218T175805Z
|
||||
UID:6a3af4de-8f0b-4e1f-a5eb-a89e12ec5c49
|
||||
SUMMARY:choral concert
|
||||
DTSTART;TZID=America/Toronto:20151214T193000
|
||||
DTEND;TZID=America/Toronto:20151214T220000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:River Run Ctr
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT1H
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T175816Z
|
||||
LAST-MODIFIED:20160218T175906Z
|
||||
DTSTAMP:20160218T175906Z
|
||||
UID:82c6a6d0-df41-47b7-a138-7aa089bd0fe7
|
||||
SUMMARY:visit Sarah
|
||||
CATEGORIES:An Outing
|
||||
DTSTART;TZID=America/Toronto:20160113T190000
|
||||
DTEND;TZID=America/Toronto:20160113T210000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:Milton
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT1H
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
LAST-MODIFIED:20160218T180006Z
|
||||
DTSTAMP:20160218T180006Z
|
||||
UID:8b0ed4cb-0414-481f-9b06-0f7bdbb915d9
|
||||
SUMMARY:play
|
||||
PRIORITY:0
|
||||
STATUS:CONFIRMED
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:ga
|
||||
rdnerw@uoguelph.ca
|
||||
CATEGORIES:An Outing
|
||||
DTSTART;TZID=America/Toronto:20160130T143000
|
||||
DTEND;TZID=America/Toronto:20160130T170000
|
||||
CLASS:PUBLIC
|
||||
LOCATION:Centre in Sq
|
||||
SEQUENCE:0
|
||||
X-YAHOO-YID:woofus
|
||||
TRANSP:OPAQUE
|
||||
X-YAHOO-USER-STATUS:BUSY
|
||||
X-YAHOO-EVENT-STATUS:BUSY
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT1H
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
X-LIC-ERROR;X-LIC-ERRORTYPE=VALUE-PARSE-ERROR:No value for DESCRIPTION pro
|
||||
perty. Removing entire property:
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T180026Z
|
||||
LAST-MODIFIED:20160218T180053Z
|
||||
DTSTAMP:20160218T180053Z
|
||||
UID:94b97c74-9f38-4f7b-8866-f68d983db10a
|
||||
SUMMARY:reading
|
||||
DTSTART;TZID=America/Toronto:20160212T100000
|
||||
DTEND;TZID=America/Toronto:20160212T120000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:library
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT15M
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T180103Z
|
||||
LAST-MODIFIED:20160218T180147Z
|
||||
DTSTAMP:20160218T180147Z
|
||||
UID:0542340e-961a-4314-8d53-1cd84c4362b3
|
||||
DTSTART;TZID=America/Toronto:20160309T080000
|
||||
DTEND;TZID=America/Toronto:20160309T170000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:home
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T180223Z
|
||||
LAST-MODIFIED:20160218T180256Z
|
||||
DTSTAMP:20160218T180256Z
|
||||
UID:78dfde7f-daf0-4eac-8c47-ce7c3d2c6134
|
||||
SUMMARY:dinner
|
||||
CATEGORIES:An Outing
|
||||
DTSTART;TZID=America/Toronto:20160321T180000
|
||||
DTEND;TZID=America/Toronto:20160321T200000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:Boston Pizza
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT30M
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T175604Z
|
||||
LAST-MODIFIED:20160218T175703Z
|
||||
DTSTAMP:20160218T175703Z
|
||||
UID:4ec7e127-7710-43ef-b330-9125741e0b4a
|
||||
SUMMARY:workout
|
||||
RRULE:FREQ=WEEKLY;UNTIL=20160601T000000Z;BYDAY=TU,TH,SA
|
||||
DTSTART;TZID=America/Toronto:20151201T163000
|
||||
DTEND;TZID=America/Toronto:20151201T173000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:gym
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT15M
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180655Z
|
||||
DTSTAMP:20160218T180655Z
|
||||
UID:3e6715c9-d01b-4166-91cb-bf9ecfc14b45
|
||||
SUMMARY:Return library book
|
||||
PRIORITY:1
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:ga
|
||||
rdnerw@uoguelph.ca
|
||||
DUE;TZID=America/Toronto:20160303T140000
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:2
|
||||
X-YAHOO-YID:woofus
|
||||
X-MOZ-GENERATION:2
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180738Z
|
||||
DTSTAMP:20160218T180738Z
|
||||
UID:1a267af7-d217-4e4e-9d14-cb998af26d36
|
||||
SUMMARY:Renew magazine subscription
|
||||
PRIORITY:0
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:ga
|
||||
rdnerw@uoguelph.ca
|
||||
DUE;TZID=America/Toronto:20160331T170000
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:0
|
||||
X-YAHOO-YID:woofus
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180836Z
|
||||
DTSTAMP:20160218T180836Z
|
||||
UID:58c98df4-1491-4df6-8888-cec2fe5761f5
|
||||
SUMMARY:Wash car
|
||||
PRIORITY:0
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:ga
|
||||
rdnerw@uoguelph.ca
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:0
|
||||
X-YAHOO-YID:woofus
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180850Z
|
||||
DTSTAMP:20160218T180850Z
|
||||
UID:474530b5-2ec4-410b-84a5-c6e7c279875f
|
||||
SUMMARY:Buy bird seed
|
||||
PRIORITY:1
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:ga
|
||||
rdnerw@uoguelph.ca
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:1
|
||||
X-YAHOO-YID:woofus
|
||||
X-MOZ-GENERATION:1
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180902Z
|
||||
DTSTAMP:20160218T180902Z
|
||||
UID:56cdb5de-94c1-4333-bfb1-00664f91aa61
|
||||
SUMMARY:Organize photos
|
||||
PRIORITY:0
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:ga
|
||||
rdnerw@uoguelph.ca
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:0
|
||||
X-YAHOO-YID:woofus
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180917Z
|
||||
DTSTAMP:20160218T180917Z
|
||||
UID:d8040743-b11e-49b9-9e9a-41708b6bc2c8
|
||||
SUMMARY:Clean out basement
|
||||
PRIORITY:9
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:ga
|
||||
rdnerw@uoguelph.ca
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:1
|
||||
X-YAHOO-YID:woofus
|
||||
X-MOZ-GENERATION:1
|
||||
END:VTODO
|
||||
END:VCALENDAR
|
||||
49
ics files/samp2.ics
Normal file
49
ics files/samp2.ics
Normal file
@@ -0,0 +1,49 @@
|
||||
BEGIN:VCALENDAR
|
||||
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
|
||||
VERSION:2.0
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:America/Toronto
|
||||
BEGIN:DAYLIGHT
|
||||
TZOFFSETFROM:-0500
|
||||
TZOFFSETTO:-0400
|
||||
TZNAME:EDT
|
||||
DTSTART:19700308T020000
|
||||
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
|
||||
END:DAYLIGHT
|
||||
BEGIN:STANDARD
|
||||
TZOFFSETFROM:-0400
|
||||
TZOFFSETTO:-0500
|
||||
TZNAME:EST
|
||||
DTSTART:19701101T020000
|
||||
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
|
||||
END:STANDARD
|
||||
END:VTIMEZONE
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T191200Z
|
||||
LAST-MODIFIED:20160218T191224Z
|
||||
DTSTAMP:20160218T191224Z
|
||||
UID:47889016-f868-4042-a374-bf93d2faedbc
|
||||
SUMMARY:midterm exam
|
||||
DTSTART;TZID=America/Toronto:20160229T123000
|
||||
DTEND;TZID=America/Toronto:20160229T132000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:RICH 2520
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT15M
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T191305Z
|
||||
DTSTAMP:20160218T191305Z
|
||||
UID:bf83033a-7568-42d1-a904-c7b9b5d067b2
|
||||
SUMMARY:study for midterm
|
||||
PRIORITY:0
|
||||
ORGANIZER;CN=Joe Young;SENT-BY="mailto:jyoung@yahoo.com":mailto:youngj
|
||||
@uoguelph.ca
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:0
|
||||
X-YAHOO-YID:jyoung
|
||||
END:VTODO
|
||||
END:VCALENDAR
|
||||
279
ics files/samp3.ics
Normal file
279
ics files/samp3.ics
Normal file
@@ -0,0 +1,279 @@
|
||||
BEGIN:VCALENDAR
|
||||
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
|
||||
VERSION:2.0
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:America/Toronto
|
||||
BEGIN:DAYLIGHT
|
||||
TZOFFSETFROM:-0500
|
||||
TZOFFSETTO:-0400
|
||||
TZNAME:EDT
|
||||
DTSTART:19700308T020000
|
||||
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
|
||||
END:DAYLIGHT
|
||||
BEGIN:STANDARD
|
||||
TZOFFSETFROM:-0400
|
||||
TZOFFSETTO:-0500
|
||||
TZNAME:EST
|
||||
DTSTART:19701101T020000
|
||||
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
|
||||
END:STANDARD
|
||||
END:VTIMEZONE
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T175508Z
|
||||
LAST-MODIFIED:20160218T175549Z
|
||||
DTSTAMP:20160218T175549Z
|
||||
UID:2c8fd444-306e-416f-98ff-6af9b3a15b9b
|
||||
SUMMARY:Xmas Eve
|
||||
DTSTART;TZID=America/Toronto:20151224T183000
|
||||
DTEND;TZID=America/Toronto:20151224T220000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:Sister's house
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT30M
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T175723Z
|
||||
LAST-MODIFIED:20160218T175805Z
|
||||
DTSTAMP:20160218T175805Z
|
||||
UID:6a3af4de-8f0b-4e1f-a5eb-a89e12ec5c49
|
||||
SUMMARY:choral concert
|
||||
DTSTART;TZID=America/Toronto:20151214T193000
|
||||
DTEND;TZID=America/Toronto:20151214T220000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:River Run Ctr
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT1H
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T175816Z
|
||||
LAST-MODIFIED:20160218T175906Z
|
||||
DTSTAMP:20160218T175906Z
|
||||
UID:82c6a6d0-df41-47b7-a138-7aa089bd0fe7
|
||||
SUMMARY:visit Sarah
|
||||
CATEGORIES:An Outing
|
||||
DTSTART;TZID=America/Toronto:20160113T190000
|
||||
DTEND;TZID=America/Toronto:20160113T210000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:Milton
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT1H
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
LAST-MODIFIED:20160218T180006Z
|
||||
DTSTAMP:20160218T180006Z
|
||||
UID:8b0ed4cb-0414-481f-9b06-0f7bdbb915d9
|
||||
SUMMARY:play
|
||||
PRIORITY:0
|
||||
STATUS:CONFIRMED
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
|
||||
erw@uoguelph.ca
|
||||
CATEGORIES:An Outing
|
||||
DTSTART;TZID=America/Toronto:20160130T143000
|
||||
DTEND;TZID=America/Toronto:20160130T170000
|
||||
CLASS:PUBLIC
|
||||
LOCATION:Centre in Sq
|
||||
SEQUENCE:0
|
||||
X-YAHOO-YID:woofus
|
||||
TRANSP:OPAQUE
|
||||
X-YAHOO-USER-STATUS:BUSY
|
||||
X-YAHOO-EVENT-STATUS:BUSY
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT1H
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
X-LIC-ERROR;X-LIC-ERRORTYPE=VALUE-PARSE-ERROR:No value for DESCRIPTION prop
|
||||
erty. Removing entire property:
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T180026Z
|
||||
LAST-MODIFIED:20160218T180053Z
|
||||
DTSTAMP:20160218T180053Z
|
||||
UID:94b97c74-9f38-4f7b-8866-f68d983db10a
|
||||
SUMMARY:reading
|
||||
DTSTART;TZID=America/Toronto:20160212T100000
|
||||
DTEND;TZID=America/Toronto:20160212T120000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:library
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT15M
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T180103Z
|
||||
LAST-MODIFIED:20160218T180147Z
|
||||
DTSTAMP:20160218T180147Z
|
||||
UID:0542340e-961a-4314-8d53-1cd84c4362b3
|
||||
DTSTART;TZID=America/Toronto:20160309T080000
|
||||
DTEND;TZID=America/Toronto:20160309T170000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:home
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T180223Z
|
||||
LAST-MODIFIED:20160218T180256Z
|
||||
DTSTAMP:20160218T180256Z
|
||||
UID:78dfde7f-daf0-4eac-8c47-ce7c3d2c6134
|
||||
SUMMARY:dinner
|
||||
CATEGORIES:An Outing
|
||||
DTSTART;TZID=America/Toronto:20160321T180000
|
||||
DTEND;TZID=America/Toronto:20160321T200000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:Boston Pizza
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT30M
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T175604Z
|
||||
LAST-MODIFIED:20160218T175703Z
|
||||
DTSTAMP:20160218T175703Z
|
||||
UID:4ec7e127-7710-43ef-b330-9125741e0b4a
|
||||
SUMMARY:workout
|
||||
RRULE:FREQ=WEEKLY;UNTIL=20160601T000000Z;BYDAY=TU,TH,SA
|
||||
DTSTART;TZID=America/Toronto:20151201T163000
|
||||
DTEND;TZID=America/Toronto:20151201T173000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:gym
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT15M
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180655Z
|
||||
DTSTAMP:20160218T180655Z
|
||||
UID:3e6715c9-d01b-4166-91cb-bf9ecfc14b45
|
||||
SUMMARY:Return library book
|
||||
PRIORITY:1
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
|
||||
erw@uoguelph.ca
|
||||
DUE;TZID=America/Toronto:20160303T140000
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:2
|
||||
X-YAHOO-YID:woofus
|
||||
X-MOZ-GENERATION:2
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180738Z
|
||||
DTSTAMP:20160218T180738Z
|
||||
UID:1a267af7-d217-4e4e-9d14-cb998af26d36
|
||||
SUMMARY:Renew magazine subscription
|
||||
PRIORITY:0
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
|
||||
erw@uoguelph.ca
|
||||
DUE;TZID=America/Toronto:20160331T170000
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:0
|
||||
X-YAHOO-YID:woofus
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180836Z
|
||||
DTSTAMP:20160218T180836Z
|
||||
UID:58c98df4-1491-4df6-8888-cec2fe5761f5
|
||||
SUMMARY:Wash car
|
||||
PRIORITY:0
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
|
||||
erw@uoguelph.ca
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:0
|
||||
X-YAHOO-YID:woofus
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180850Z
|
||||
DTSTAMP:20160218T180850Z
|
||||
UID:474530b5-2ec4-410b-84a5-c6e7c279875f
|
||||
SUMMARY:Buy bird seed
|
||||
PRIORITY:1
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
|
||||
erw@uoguelph.ca
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:1
|
||||
X-YAHOO-YID:woofus
|
||||
X-MOZ-GENERATION:1
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180902Z
|
||||
DTSTAMP:20160218T180902Z
|
||||
UID:56cdb5de-94c1-4333-bfb1-00664f91aa61
|
||||
SUMMARY:Organize photos
|
||||
PRIORITY:0
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
|
||||
erw@uoguelph.ca
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:0
|
||||
X-YAHOO-YID:woofus
|
||||
END:VTODO
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T180917Z
|
||||
DTSTAMP:20160218T180917Z
|
||||
UID:d8040743-b11e-49b9-9e9a-41708b6bc2c8
|
||||
SUMMARY:Clean out basement
|
||||
PRIORITY:9
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
|
||||
erw@uoguelph.ca
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:1
|
||||
X-YAHOO-YID:woofus
|
||||
X-MOZ-GENERATION:1
|
||||
END:VTODO
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:America/Toronto
|
||||
BEGIN:DAYLIGHT
|
||||
TZOFFSETFROM:-0500
|
||||
TZOFFSETTO:-0400
|
||||
TZNAME:EDT
|
||||
DTSTART:19700308T020000
|
||||
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
|
||||
END:DAYLIGHT
|
||||
BEGIN:STANDARD
|
||||
TZOFFSETFROM:-0400
|
||||
TZOFFSETTO:-0500
|
||||
TZNAME:EST
|
||||
DTSTART:19701101T020000
|
||||
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
|
||||
END:STANDARD
|
||||
END:VTIMEZONE
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T191200Z
|
||||
LAST-MODIFIED:20160218T191224Z
|
||||
DTSTAMP:20160218T191224Z
|
||||
UID:47889016-f868-4042-a374-bf93d2faedbc
|
||||
SUMMARY:midterm exam
|
||||
DTSTART;TZID=America/Toronto:20160229T123000
|
||||
DTEND;TZID=America/Toronto:20160229T132000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:RICH 2520
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT15M
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VTODO
|
||||
LAST-MODIFIED:20160218T191305Z
|
||||
DTSTAMP:20160218T191305Z
|
||||
UID:bf83033a-7568-42d1-a904-c7b9b5d067b2
|
||||
SUMMARY:study for midterm
|
||||
PRIORITY:0
|
||||
ORGANIZER;CN=Joe Young;SENT-BY="mailto:jyoung@yahoo.com":mailto:youngj@uogu
|
||||
elph.ca
|
||||
CLASS:PUBLIC
|
||||
SEQUENCE:0
|
||||
X-YAHOO-YID:jyoung
|
||||
END:VTODO
|
||||
END:VCALENDAR
|
||||
140
ics files/samp4.ics
Normal file
140
ics files/samp4.ics
Normal file
@@ -0,0 +1,140 @@
|
||||
BEGIN:VCALENDAR
|
||||
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
|
||||
VERSION:2.0
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T175508Z
|
||||
LAST-MODIFIED:20160218T175549Z
|
||||
DTSTAMP:20160218T175549Z
|
||||
UID:2c8fd444-306e-416f-98ff-6af9b3a15b9b
|
||||
SUMMARY:Xmas Eve
|
||||
DTSTART;TZID=America/Toronto:20151224T183000
|
||||
DTEND;TZID=America/Toronto:20151224T220000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:Sister's house
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT30M
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T175723Z
|
||||
LAST-MODIFIED:20160218T175805Z
|
||||
DTSTAMP:20160218T175805Z
|
||||
UID:6a3af4de-8f0b-4e1f-a5eb-a89e12ec5c49
|
||||
SUMMARY:choral concert
|
||||
DTSTART;TZID=America/Toronto:20151214T193000
|
||||
DTEND;TZID=America/Toronto:20151214T220000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:River Run Ctr
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT1H
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T175816Z
|
||||
LAST-MODIFIED:20160218T175906Z
|
||||
DTSTAMP:20160218T175906Z
|
||||
UID:82c6a6d0-df41-47b7-a138-7aa089bd0fe7
|
||||
SUMMARY:visit Sarah
|
||||
CATEGORIES:An Outing
|
||||
DTSTART;TZID=America/Toronto:20160113T190000
|
||||
DTEND;TZID=America/Toronto:20160113T210000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:Milton
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT1H
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
LAST-MODIFIED:20160218T180006Z
|
||||
DTSTAMP:20160218T180006Z
|
||||
UID:8b0ed4cb-0414-481f-9b06-0f7bdbb915d9
|
||||
SUMMARY:play
|
||||
PRIORITY:0
|
||||
STATUS:CONFIRMED
|
||||
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
|
||||
erw@uoguelph.ca
|
||||
CATEGORIES:An Outing
|
||||
DTSTART;TZID=America/Toronto:20160130T143000
|
||||
DTEND;TZID=America/Toronto:20160130T170000
|
||||
CLASS:PUBLIC
|
||||
LOCATION:Centre in Sq
|
||||
SEQUENCE:0
|
||||
X-YAHOO-YID:woofus
|
||||
TRANSP:OPAQUE
|
||||
X-YAHOO-USER-STATUS:BUSY
|
||||
X-YAHOO-EVENT-STATUS:BUSY
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT1H
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
X-LIC-ERROR;X-LIC-ERRORTYPE=VALUE-PARSE-ERROR:No value for DESCRIPTION prop
|
||||
erty. Removing entire property:
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T180026Z
|
||||
LAST-MODIFIED:20160218T180053Z
|
||||
DTSTAMP:20160218T180053Z
|
||||
UID:94b97c74-9f38-4f7b-8866-f68d983db10a
|
||||
SUMMARY:reading
|
||||
DTSTART;TZID=America/Toronto:20160212T100000
|
||||
DTEND;TZID=America/Toronto:20160212T120000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:library
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT15M
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T180103Z
|
||||
LAST-MODIFIED:20160218T180147Z
|
||||
DTSTAMP:20160218T180147Z
|
||||
UID:0542340e-961a-4314-8d53-1cd84c4362b3
|
||||
DTSTART;TZID=America/Toronto:20160309T080000
|
||||
DTEND;TZID=America/Toronto:20160309T170000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:home
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T180223Z
|
||||
LAST-MODIFIED:20160218T180256Z
|
||||
DTSTAMP:20160218T180256Z
|
||||
UID:78dfde7f-daf0-4eac-8c47-ce7c3d2c6134
|
||||
SUMMARY:dinner
|
||||
CATEGORIES:An Outing
|
||||
DTSTART;TZID=America/Toronto:20160321T180000
|
||||
DTEND;TZID=America/Toronto:20160321T200000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:Boston Pizza
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT30M
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
CREATED:20160218T175604Z
|
||||
LAST-MODIFIED:20160218T175703Z
|
||||
DTSTAMP:20160218T175703Z
|
||||
UID:4ec7e127-7710-43ef-b330-9125741e0b4a
|
||||
SUMMARY:workout
|
||||
RRULE:FREQ=WEEKLY;UNTIL=20160601T000000Z;BYDAY=TU,TH,SA
|
||||
DTSTART;TZID=America/Toronto:20151201T163000
|
||||
DTEND;TZID=America/Toronto:20151201T173000
|
||||
TRANSP:OPAQUE
|
||||
LOCATION:gym
|
||||
BEGIN:VALARM
|
||||
ACTION:DISPLAY
|
||||
TRIGGER;VALUE=DURATION:-PT15M
|
||||
DESCRIPTION:Default Mozilla Description
|
||||
END:VALARM
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
0
ics files/test.ics
Normal file
0
ics files/test.ics
Normal file
19
makefile
Normal file
19
makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -std=c11 -g -fPIC `pkg-config --cflags python3`
|
||||
LDFLAGS =
|
||||
|
||||
all: caltool Cal.so
|
||||
|
||||
caltool: caltool.o calutil.o
|
||||
|
||||
caltool.o: caltool.c caltool.h
|
||||
|
||||
calutil.o: calutil.c calutil.h
|
||||
|
||||
Cal.so: calmodule.o calutil.o
|
||||
$(CC) -shared $^ $(LDFLAGS) -o $@
|
||||
|
||||
calmodule.o: calmodule.c calutil.h
|
||||
|
||||
clean:
|
||||
rm -f *.o caltool Cal.so
|
||||
Reference in New Issue
Block a user