diff options
Diffstat (limited to 'libkcal/versit')
-rw-r--r-- | libkcal/versit/Makefile.am | 6 | ||||
-rw-r--r-- | libkcal/versit/port.h | 75 | ||||
-rw-r--r-- | libkcal/versit/readme.txt | 944 | ||||
-rw-r--r-- | libkcal/versit/vcc.c | 2498 | ||||
-rw-r--r-- | libkcal/versit/vcc.h | 76 | ||||
-rw-r--r-- | libkcal/versit/vcc.y | 1232 | ||||
-rw-r--r-- | libkcal/versit/vobject.c | 1429 | ||||
-rw-r--r-- | libkcal/versit/vobject.h | 384 |
8 files changed, 6644 insertions, 0 deletions
diff --git a/libkcal/versit/Makefile.am b/libkcal/versit/Makefile.am new file mode 100644 index 000000000..0f283ede6 --- /dev/null +++ b/libkcal/versit/Makefile.am @@ -0,0 +1,6 @@ +# $Id$ + +noinst_LTLIBRARIES = libversit.la + +libversit_la_SOURCES = vcc.c vobject.c + diff --git a/libkcal/versit/port.h b/libkcal/versit/port.h new file mode 100644 index 000000000..afc16dd42 --- /dev/null +++ b/libkcal/versit/port.h @@ -0,0 +1,75 @@ +/*************************************************************************** +(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International +Business Machines Corporation and Siemens Rolm Communications Inc. + +For purposes of this license notice, the term Licensors shall mean, +collectively, Apple Computer, Inc., AT&T Corp., International +Business Machines Corporation and Siemens Rolm Communications Inc. +The term Licensor shall mean any of the Licensors. + +Subject to acceptance of the following conditions, permission is hereby +granted by Licensors without the need for written agreement and without +license or royalty fees, to use, copy, modify and distribute this +software for any purpose. + +The above copyright notice and the following four paragraphs must be +reproduced in all copies of this software and any software including +this software. + +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE +ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR +MODIFICATIONS. + +IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, +INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT +OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. + +The software is provided with RESTRICTED RIGHTS. Use, duplication, or +disclosure by the government are subject to restrictions set forth in +DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. + +***************************************************************************/ + +#ifndef __PORT_H__ +#define __PORT_H__ 1 + +#if defined(__CPLUSPLUS__) || defined(__cplusplus) +extern "C" { +#endif + +#define vCardClipboardFormat "+//ISBN 1-887687-00-9::versit::PDI//vCard" +#define vCalendarClipboardFormat "+//ISBN 1-887687-00-9::versit::PDI//vCalendar" + +/* The above strings vCardClipboardFormat and vCalendarClipboardFormat +are globally unique IDs which can be used to generate clipboard format +ID's as per the requirements of a specific platform. For example, in +Windows they are used as the parameter in a call to RegisterClipboardFormat. +For example: + + CLIPFORMAT foo = RegisterClipboardFormat(vCardClipboardFormat); + +*/ + +#define vCardMimeType "text/x-vCard" +#define vCalendarMimeType "text/x-vCalendar" + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +#define Parse_Debug(t) + +#if defined(__CPLUSPLUS__) || defined(__cplusplus) +} +#endif + +#endif /* __PORT_H__ */ diff --git a/libkcal/versit/readme.txt b/libkcal/versit/readme.txt new file mode 100644 index 000000000..5f38fe005 --- /dev/null +++ b/libkcal/versit/readme.txt @@ -0,0 +1,944 @@ +The vCard/vCalendar C interface is implemented in the set +of files as follows: + +vcc.y, yacc source, and vcc.c, the yacc output you will use +implements the core parser + +vobject.c implements an API that insulates the caller from +the parser and changes in the vCard/vCalendar BNF + +port.h defines compilation environment dependent stuff + +vcc.h and vobject.h are header files for their .c counterparts + +vcaltmp.h and vcaltmp.c implement vCalendar "macro" functions +which you may find useful. + +test.c is a standalone test driver that exercises some of +the features of the APIs provided. Invoke test.exe on a +VCARD/VCALENDAR input text file and you will see the pretty +print output of the internal representation (this pretty print +output should give you a good idea of how the internal +representation looks like -- there is one such output in the +following too). Also, a file with the .out suffix is generated +to show that the internal representation can be written back +in the original text format. + +----------------------------------------------------------------- + + + VObject for VCard/VCalendar + +Table of Contents +================= +1. VObject +2. Internal Representations of VCard/VCalendar +3. Iterating Through VObject's Properties or Values +4. Pretty Printing a VObject Tree +5. Building A VObject Representation of A VCard/VCalendar +6. Converting A VObject Representation Into Its Textual Representation +7. Miscellaneous Notes On VObject APIs usages +8. Brief descriptions of each APIs +9. Additional Programming Notes. + +This document is mainly about the VObject and its APIs. The main +use of a VObject is to represent a VCard or a VCalendar inside +a program. However, its use is not limited to aforemention as it +can represent an arbitrary information that makes up of a tree or +forest of properties/values. + +1. VObject + ======= +A VObject can have a name (id) and a list of associated properties and +a value. Each property is itself a VObject. + +2. Internal Representations of VCard/VCalendar + =========================================== +A list of VCard or a VCalendar is represented by a list of VObjects. +The name (id) of the VObjects in the list is either VCCardProp or +VCCalProp. Each of these VObjects can have a list of properties. +Since a property is represented as a VObject, each of these properties +can have a name, a list of properties, and a value. + +For example, the input file "vobject.vcf": + +BEGIN:VCARD +N:Alden;Roland +FN:Roland H. Alden +ORG:AT&T;Versit Project Office +TITLE:Consultant +EMAIL;WORK;PREF;INTERNET:sf!rincon!ralden@alden.attmail.com +EMAIL;INTERNET:ralden@sfgate.com +EMAIL;MCIMail:242-2200 +LABEL;DOM;POSTAL;PARCEL;HOME;WORK;QUOTED-PRINTABLE:Roland H. Alden=0A= +Suite 2208=0A= +One Pine Street=0A= +San Francisco, CA 94111 +LABEL;POSTAL;PARCEL;HOME;WORK;QUOTED-PRINTABLE:Roland H. Alden=0A= +Suite 2208=0A= +One Pine Street=0A= +San Francisco, CA 94111=0A= +U.S.A. +TEL;WORK;PREF;MSG:+1 415 296 9106 +TEL;WORK;FAX:+1 415 296 9016 +TEL;MSG;CELL:+1 415 608 5981 +ADR:;Suite 2208;One Pine Street;San Francisco;CA;94111;U.S.A. +SOUND:ROW-LAND H ALL-DIN +LOGO;GIF;BASE64: + R0lGODdhpgBOAMQAAP///+/v797e3s7Ozr29va2trZycnIyMjHt7e2NjY1JSUkJC + QjExMSEhIRAQEO///87v9973/73n95zW71K13jGl1nvG50Kt3iGc1gCMzq3e94zO + 7xCU1nO952O15wAAACwAAAAApgBOAAAF/yAgjmRpnmiqrmzrvnAsz3Rt33iu73zv + /8CgcEj8QTaeywWTyWCUno2kSK0KI5tLc8vtNi+WiHVMlj0mFK96nalsxOW4fPSw + cNj4tQc+7xcjGh4WExJTJYUTFkp3eU0eEH6RkpOUlTARhRoWm5ydFpCWoS0QEqAu + ARKaHRcVjV0borEoFl0cSre4Sq67FA+yvwAeTU8XHZ7HmxS6u2wVfMCVpAE3pJoW + ylrMptDcOqSF4OHg3eQ5pInInb7lcc86mNbLzBXsZbRfUOn6ucyNHvVWJHCpQFDf + MWwEEzLqx2YCQCqF3OnItClJNmYcJD7cSAKTuI/gtnEcOQKkyVIk6/+ds5CkFcMM + 61LiENikwi1jBnNyuvUSjwWZOS5uIZarqNFcNl32XMMB6I06GgoJ+bZp1ZKeDl8E + +MC1K1cBIhZ4HUu2LAsCZdOWRQDt20lxIlccSHsgrNq7Xc/ixcsWmNu34WKyYJCW + gQjCe9XqTZy2L4pv04gg2sSKSc8OLgTcBSuWsdkVaD2TdXyiQxebFyjo1Gnx6tJm + LuaqrdtZtNfFtruSNmF5IKujwIsmJbjwtRqNJhrcNVw79wcRAgogmE4ArIjQzj/s + JvHAGCFDQR4UqigPK4sBe62XwO51OwADiMcqUG+iOdcFAL+hW20BfAoEexlwAnu6 + mZDAXQ1EVh//WfhxJB5gIbHgwFgOTOiVAgOuVQKAfKFg3weGwSBYFZMp4hpDGKyA + 3lgJKECWgiMQyBVpW+0V4oJjNfhCNkR1IgWEb21QlRK9GdfFCgeOZYBsXgm4noYj + GEBhAQHYh0J8XenoQnFGdrkUciJY6FUAK15ogozakcBhliKsyZWHDMZQ0wWC/Aim + DB6h01KRr/lXQgFxAqDcWDACgCZpUnrVQJtjwTnWjS6MWAYqqfDnSaEkJOlVXQBo + 2pWTMUJ53WgAuPncCR9q6VQMAYjZlXWJmknCoSUM2p4BC+SaKwG88hoZlvfFMM4f + hQh5TXkv+RklWYtC91mopJIAKFkJlDAW/wF25ShnLbeo5gmQ+1FGkJdrKCuCi2OR + BuwHBcwqKgABrMtVAgpem61XkLbAJ7n8uiIpvGVhO4KpH1QLbbpqLheZvQCkGoNL + thSzSTg2UGVBBzbtaxwKsYrmgLvRAlCmWgwMAADD66rKAgR3XlGspcdkZYK8ibU7 + asgEl+XAyB8I7PCqMWiWncGGimpfAgO4ypXSPpOVLwsRCDJxRD2AoyeRRv5kApO5 + fXwzwvfOKLKtaTWtbQxccmGLTZy8xYlVSvXbhbk0M2YzrYfJJ0K8m+V9NgxpyC04 + UycI/aiuiH9Y8NftDUwWp1Wm5UABnAUKwwRsPFGBt4Oc9PZvGvNLwf8JOZt8Arpe + eY23yDovwIDiBX74NAsPVLDJj3Hh4JEExsKcjrlKf9DsCVx3ZfLqAKBuG1s/A90C + z2KjYHjjyPOdG1spz6BBUr+BcUxUb1nDCTa/VZD2Uv+YkLPAKJC9dNEh7628WgqI + ybzlaA+ufxMa6bxC6ciLUQLcx5UGIAAsAkDA6wQkOxrcY39yo4cQMNWCAPTKV1R4 + wPkgaBxzOc8FtMiF1NoGoXBRJjgoPApmPsjCFlbMdzCM4TFy50IXxI2DPcHAv2rY + gghsEIeu8CAPW6ABIPYEFkOsAeaMyIz0JfGJUExBBGRIRX0IMYovWCIT1eBELNpA + i1vcgta8iANPCIQOghzQABl30J0tXqBla4wjFLFQxZzAUY42CIAd5OYBCuKxB2c4 + I0b28EcrQKADgmSKB9RYyDhA4BqCxIBqrtjIMTwoFeCjYSU3KZMQAAA7 + +BEGIN:VCALENDAR +DCREATED:19960523T100522 +PRODID:-//Alden Roland/Hand Crafted In North Carolina//NONSGML Made By Hand//EN +VERSION:0.3 +BEGIN:VEVENT +START:19960523T120000 +END:19960523T130000 +SUBTYPE:PHONE CALL +SUMMARY:VERSIT PDI PR Teleconference/Interview +DESCRIPTION:VERSIT PDI PR Teleconference/Interview With Tom Streeter and Alden Roland +END:VEVENT +BEGIN:VEVENT +START:19960523T113000 +END:19960523T115500 +SUBTYPE:LUNCH +SUMMARY:Eat in the cafeteria today +END:VEVENT +END:VCALENDAR + +END:VCARD + + +will conceptually be be represented as + vcard + VCNameProp + VCFamilyNameProp=Alden + VCGivenNameProp=Roland + VCFullNameProp=Roland H.Alden + .... + +note that + EMAIL;WORK;PREF;INTERNET:sf!rincon!ralden@alden.attmail.com +will be represented as: + VCEmailAddress=sf!rincon!ralden@alden.attmail.com + VCWork + VCPreferred + VCInternet +where the lower level properties are properties of the property +VCEmailAddress. + +Groupings are flattened out in the VObject representation such +that: + a.b:blah + a.c:blahblah +are represented as: + b=blah + VCGrouping=a + c=blahblah + VCGrouping=a +i.e. one can read the above as: + the property "b" has value "blah" and property "VCGrouping" + with the value "a". + the property "c" has value "blahblah" and property "VCGrouping" + with the value "a". +likewise, multi-level groupings are flatten similarly. e.g. + a.b.c:blah + a.b.e:blahblah +--> + c=blah + VCGrouping=b + VCGrouping=a + e=blahblah + VCGrouping=b + VCGrouping=a +which read: + the property "c" has value "blah" and property "VCGrouping" + with the value "b" which has property "VCGrouping" + with value "a". + the property "e" has value "blahblah" and property "VCGrouping" + with the value "b" which has property "VCGrouping" + with value "a". + +3. Iterating Through VObject's Properties or Values + ================================================ +The following is a skeletal form of iterating through +all properties of a vobject, o: + + // assume the object of interest, o, is of type VObject + VObjectIterator i; + initPropIterator(&i,o); + while (moreIteration(&i)) { + VObject *each = nextVObject(&i); + // ... do something with "each" property + } + +Use the API vObjectName() to access a VObject's name. +Use the API vObjectValueType() to determine if a VObject has + a value. For VCard/VCalendar application, you + should not need this function as practically + all values are either of type VCVT_USTRINGZ or + VCVT_RAW (i.e set by setVObjectUStringZValue and + setVObjectAnyValue APIs respectively), and the + value returned by calls to vObjectUStringZValue + and vObjectAnyValue are 0 if a VObject has no + value. (There is a minor exception where VObject with + VCDataSizeProp has value that is set by + setVObjectLongValue). +Use the APIs vObject???Value() to access a VObject's value. + where ??? is the expected type. +Use the APIs setvObject???Value() to set or modify a VObject's value. + where ??? is the expected type. +Use the API isAPropertyOf() to query if a name match the name of + a property of a VObject. Since isAPropertyOf() return + the matching property, we can use that to retrieve + a property and subsequently the value of the property. + +4. Pretty Printing a VObject Tree + ============================== +VObject tree can be pretty printed with the printVObject() function. +The output of pretty printing a VObject representation of the input +test file "vobject.vcf" is shown below. Note that the indentation +indicates the tree hirerarchy where the immediate children nodes +of a parent node is all at the same indentation level and the +immediate children nodes are the immediate properties of the +associated parent nodes. In the following, {N,FN,ORG,TITLE,...} +are immediate properties of VCARD. {F and G} are properties of N +with value {"Alden" and "Roland"} respectively; FN has no property +but has the value "Roland H. Alden"; EMAIL has value and +the properties WORK, PREF, and INTERNET. + + +VCARD + N + F="Alden" + G="Roland" + FN="Roland H. Alden" + ORG + ORGNAME="AT&T" + OUN="Versit Project Office" + TITLE="Consultant" + EMAIL="sf!rincon!ralden@alden.attmail.com" + WORK + PREF + INTERNET + EMAIL="ralden@sfgate.com" + INTERNET + EMAIL="242-2200" + MCIMail + LABEL="Roland H. Alden + Suite 2208 + One Pine Street + San Francisco, CA 94111" + DOM + POSTAL + PARCEL + HOME + WORK + QP + LABEL="Roland H. Alden + Suite 2208 + One Pine Street + San Francisco, CA 94111 + U.S.A." + POSTAL + PARCEL + HOME + WORK + QP + TEL="+1 415 296 9106" + WORK + PREF + MSG + TEL="+1 415 296 9016" + WORK + FAX + TEL="+1 415 608 5981" + MSG + CELL + ADR + EXT ADD="Suite 2208" + STREET="One Pine Street" + L="San Francisco" + R="CA" + PC="94111" + C="U.S.A." + SOUND="ROW-LAND H ALL-DIN" + LOGO=[raw data] + GIF + BASE64 + DataSize=1482 +VCALENDAR + DCREATED="19960523T100522" + PRODID="-//Alden Roland/Hand Crafted In North Carolina//NONSGML Made By Hand//EN" + VERSION="0.3" + VEVENT + START="19960523T120000" + END="19960523T130000" + SUBTYPE="PHONE CALL" + SUMMARY="VERSIT PDI PR Teleconference/Interview" + DESCRIPTION="VERSIT PDI PR Teleconference/Interview With Tom Streeter and Alden Roland" + VEVENT + START="19960523T113000" + END="19960523T115500" + SUBTYPE="LUNCH" + SUMMARY="Eat in the cafeteria today" + +5. Building A VObject Representation of A VCard/VCalendar + ====================================================== +The parser in vcc.y converts an input file with one or more +VCard/VCalendar that is in their textual representation +into their corresponding VObject representation. + +VObject representation of a VCard/VCalendar can also be built +directly with calls to the VObject building APIs. e.g. + + VObject *prop; + VObject *vcard = newVObject(VCCardProp); + prop = addProp(vcard,VCNameProp); + addPropValue(prop,VCFamilyNameProp,"Alden"); + addPropValue(prop,VCGivenNameProp,"Roland"); + addPropValue(vcard,VCFullNameProp,"Roland H. Alden"); + .... + +6. Converting A VObject Representation Into Its Textual Representation + =================================================================== +The VObject representation can be converted back to its textual +representation via the call to writeVObject() or writeMemVObject() +API. e.g. + a. to write to a file: + // assume vcard is of type VObject + FILE *fp = fopen("alden.vcf","w"); + writeVObject(fp,vcard); + a. to write to memory, and let the API allocate the required memory. + char* clipboard = writeVObject(0,0,vcard); + ... do something to clipboard + free(clipboard); + b. to write to a user allocated buffer: + char clipboard[16384]; + int len = 16384; + char *buf = writeVObject(clipboard,&len,vcard); + ... buf will be equal to clipboard if the write + is successful otherwise 0. + +In the case of writing to memory, the memory buffer can be either +allocated by the API or the user. If the user allocate the +memory for the buffer, then the length of the buffer needs to be +communicated to the API via a variable. The variable passed as +the length argument will be overwritten with the actual size +of the text output. A 0 return value from writeMemVObject() +indicates an error which could be caused by overflowing the +size of the buffer or lack of heap memory. + +7. Miscellaneous Notes On VObject APIs usages + ========================================== +a. vcc.h -- contains basic interfaces to the parser: + VObject* Parse_MIME(const char *input, unsigned long len); + VObject* Parse_MIME_FromFile(FILE *file); + -- both of this return a null-terminated list of + VObject that is either a VCARD or VCALENDAR. + To iterate through this list, do + VObject *t, *v; + v = Parse_Mime_FromFile(fp); + while (v) { + // ... do something to v. + t = v; + v = nextVObjectInList(v); + cleanVObject(t); + } + note that call to cleanVObject will release + resource used to represent the VObject. + +b. vobject.h -- contains basic interfaces to the VObject APIs. + see the header for more details. + The structure of VObject is purposely (hiddened) not exposed + to the user. Every access has to be done via + the APIs. This way, if we need to change the + structure or implementation, the client need not + recompile as long as the interfaces remain the + same. + +c. values of a property is determined by the property definition + itself. The vobject APIs does not attempt to enforce + any of such definition. It is the consumer responsibility + to know what value is expected from a property. e.g + most properties have unicode string value, so to access + the value of these type of properties, you will use + the vObjectUStringZValue() to read the value and + setVObjectUStringZValue() to set or modify the value. + Refer to the VCard and VCalendar specifications for + the definition of each property. + +d. properties name (id) are case incensitive. + +8. Brief descriptions of each APIs + =============================== + * the predefined properties' names (id) are listed under vobject.h + each is of the form VC*Prop. e.g. + #define VC7bitProp "7BIT" + #define VCAAlarmProp "AALARM" + .... + + * consumer of a VObject can only define pointers to VObject. + + * a variable of type VObjectIterator, say "i", can be used to iterate + through a VObject's properties, say "o". The APIs related to + VObjectIterator are: + void initPropIterator(VObjectIterator *i, VObject *o); + -- e.g. usage + initPropIterator(&i,o); + int moreIteration(VObjectIterator *i); + -- e.g. usage + while (moreIteration(&i)) { ... } + VObject* nextVObject(VObjectIterator *i); + -- e.g. usage + while (moreIteration(&i)) { + VObject *each = nextVObject(&i); + } + + * VObject can be chained together to form a list. e.g. of such + use is in the parser where the return value of the parser is + a link list of VObject. A link list of VObject can be + built by: + void addList(VObject **o, VObject *p); + and iterated by + VObject* nextVObjectInList(VObject *o); + -- next VObjectInList return 0 if the list + is exhausted. + + * the following APIs are mainly used to construct a VObject tree: + VObject* newVObject(const char *id); + -- used extensively internally by VObject APIs but when + used externally, its use is mainly limited to the + construction of top level object (e.g. an object + with VCCardProp or VCCalendarProp id). + + void deleteVObject(VObject *p); + -- to deallocate single VObject, for most user, use + cleanVObject(VObject *o) instead for freeing all + resources associated with the VObject. + + char* dupStr(const char *s, unsigned int size); + -- duplicate a string s. If size is 0, the string is + assume to be a null-terminated. + + void deleteStr(const char *p); + -- used to deallocate a string allocated by dupStr(); + + void setVObjectName(VObject *o, const char* id); + -- set the id of VObject o. This function is not + normally used by the user. The setting of id + is normally done as part of other APIs (e.g. + addProp()). + + void setVObjectStringZValue(VObject *o, const char *s); + -- set a string value of a VObject. + + void setVObjectUStringZValue(VObject *o, const wchar_t *s); + -- set a Unicode string value of a VObject. + + void setVObjectIntegerValue(VObject *o, unsigned int i); + -- set an integer value of a VObject. + + void setVObjectLongValue(VObject *o, unsigned long l); + -- set an long integer value of a VObject. + + void setVObjectAnyValue(VObject *o, void *t); + -- set any value of a VObject. The value type is + unspecified. + + VObject* setValueWithSize(VObject *prop, void *val, unsigned int size); + -- set a raw data (stream of bytes) value of a VObject + whose size is size. The internal VObject representation + is + this object = val + VCDataSizeProp=size + i.e. the value val will be attached to the VObject prop + and a property of VCDataSize whose value is size + is also added to the object. + + void setVObjectVObjectValue(VObject *o, VObject *p); + -- set a VObject as the value of another VObject. + + const char* vObjectName(VObject *o); + -- retrieve the VObject's Name (i.e. id). + + const char* vObjectStringZValue(VObject *o); + -- retrieve the VObject's value interpreted as + null-terminated string. + + const wchar_t* vObjectUStringZValue(VObject *o); + -- retrieve the VObject's value interpreted as + null-terminated unicode string. + + unsigned int vObjectIntegerValue(VObject *o); + -- retrieve the VObject's value interpreted as + integer. + + unsigned long vObjectLongValue(VObject *o); + -- retrieve the VObject's value interpreted as + long integer. + + void* vObjectAnyValue(VObject *o); + -- retrieve the VObject's value interpreted as + any value. + + VObject* vObjectVObjectValue(VObject *o); + -- retrieve the VObject's value interpreted as + a VObject. + + VObject* addVObjectProp(VObject *o, VObject *p); + -- add a VObject p as a property of VObject o. + (not normally used externally for building a + VObject). + + VObject* addProp(VObject *o, const char *id); + -- add a property whose name is id to VObject o. + + VObject* addPropValue(VObject *o, const char *id, const char *v); + -- add a property whose name is id and whose value + is a null-terminated string to VObject o. + + VObject* addPropSizedValue(VObject *o, const char *id, + const char *v, unsigned int size); + -- add a property whose name is id and whose value + is a stream of bytes of size size, to VObject o. + + VObject* addGroup(VObject *o, const char *g); + -- add a group g to VObject o. + e.g. if g is a.b.c, you will have + o + c + VCGroupingProp=b + VCGroupingProp=a + and the object c is returned. + + VObject* isAPropertyOf(VObject *o, const char *id); + -- query if a property by the name id is in o and + return the VObject that represent that property. + + void printVObject(VObject *o); + -- pretty print VObject o to stdout (for debugging use). + + void writeVObject(FILE *fp, VObject *o); + -- convert VObject o to its textual representation and + write it to file. + + char* writeMemVObject(char *s, int *len, VObject *o); + -- convert VObject o to its textual representation and + write it to memory. If s is 0, then memory required + to hold the textual representation will be allocated + by this API. If a variable len is passed, len will + be overwriten with the byte size of the textual + representation. If s is non-zero, then s has to + be a user allocated buffer whose size has be passed + in len as a variable. Memory allocated by the API + has to be freed with call to free. The return value + of this API is either the user supplied buffer, + the memory allocated by the API, or 0 (in case of + failure). + + void cleanStrTbl(); + -- this function has to be called when all + VObject has been destroyed. + + void cleanVObject(VObject *o); + -- release all resources used by VObject o. + + wchar_t* fakeUnicode(const char *ps, int *bytes); + -- convert char* to wchar_t*. + + extern int uStrLen(const wchar_t *u); + -- length of unicode u. + + char *fakeCString(const wchar_t *u); + -- convert wchar_t to CString (blindly assumes that + this could be done). + +9. Additional Programming Notes + ============================ +In the following notes, please refers to the listing +of Example.vcf and its VObject Representation +(shown at the end of this section). + +* Handling the Return Value of the VCard/VCalendar Parser + The example input text file contains two root VObjects + (a VCalendar and a VCard). The output of the VCard/VCalendar + parser is a null-terminated list of VObjects. For this + particular input file, the list will have two VObjects. + The following shows a template for iterating through the + output of the Parser: + + VObject *t, *v; + v = Parse_Mime_fromFileName("example.vcf"); + while (v) { + // currently, v will either be a VCard or a VCalendar + // do whatever your application need to do to + // v here ... + t = v; + v = nextVObjectInList(v); + cleanVObject(t); + } + +* Iterating Through a VCard/VCalendar VObject + From the VObject APIs point of view, a VCard VObject + is the same as a VCalendar VObject. However, the application + needs to know what are in a VCard or a VCalendar. + For example, A VCalendar VObject can have VCDCreatedProp, + a VCGEOLocationProp, etc, and one or more VCEventProp and + or VCTodoProp. The VCEventProp and VCTodoProp can have + many properties of their own, which in turn could have + more properties (e.g. VCDAlarmProp can be a VCEventProp + VObject's property, and VCRunTimeProp can be a + VCDAlarmProp VObject's property. Because a VObject tree + can be arbitrarily complex, in general, to process all + properties and values of a VObject tree, a recursive walk + is desirable. An example recursive VObject tree walk + can be found in the vobject.c source lines for printVObject* + and writeVObject* APIs. Depending on what the application need + to do with a VCard or a VCalendar, a recursive walk + of the VObject tree may or may not be desirable. An example + template of a non-recursive walk is shown below: + + void processVCardVCalendar(char *inputFile) + { + VObject *t, *v; + v = Parse_Mime_fromFileName(inputFile); + while (v) { + char *n = vObjectName(v); + if (strcmp(n,VCCardProp) == 0) { + do_VCard(v); + } + else if (strcmp(n,VCCalendarProp) == 0) { + do_VCalendar(v); + } + else { + // don't know how to handle anything else! + } + t = v; + v = nextVObjectInList(v); + cleanVObject(t); + } + } + + void do_VCard(VObject *vcard) + { + VObjectIterator t; + initPropIterator(&t,vcard); + while (moreIteration(&t)) { + VObject *eachProp = nextVObject(&t); + // The primarly purpose of this example is to + // show how to iterate through a VCard VObject, + // it is not meant to be efficient at all. + char *n = vObjectName(eachProp); + if (strcmp(n,VCNameProp)==0) { + do_name(eachProp); + } + else if (strcmp(n,VCEmailProp)==0) { + do_email(eachProp); + } + else if (strcmp(n,VCLabelProp)==0) { + do_label(eachProp); + } + else if .... + } + } + + void do_VCalendar(VObject *vcal) + { + VObjectIterator t; + initPropIterator(&t,vcard); + while (moreIteration(&t)) { + VObject *eachProp = nextVObject(&t); + // The primarly purpose of this example is to + // show how to iterate through a VCalendar VObject, + // it is not meant to be efficient at all. + char *n = vObjectName(eachProp); + if (strcmp(n,VCDCreatedProp)==0) { + do_DCreated(eachProp); + } + else if (strcmp(n,VCVersionProp)==0) { + do_Version(eachProp); + } + else if (strcmp(n,VCTodoProp)==0) { + do_Todo(eachProp); + } + else if (strcmp(n,VCEventProp)==0) { + do_Event(eachProp); + } + else if .... + } + } + + void do_Todo(VObject *vtodo) { ... } + + void do_Event(VObject *vevent) { ... } + + ... + +* Property's Values and Properties + The VObject APIs do not attempt to check for the + correctness of the values of a property. Nor do they + will prevent the user from attaching a non-VCard/VCalendar + standard property to a VCard/VCalendar property. Take + the example of line [11] of the example, "O.K" is not + a valid value of VCStatusProp. It is up to the application + to accept or reject the value of a property. + +* Output of printVObject + PrintVObject pretty prints a VObject tree in human + readable form. See the listing at the end of the file + for an example output of printVObject on the example + input file "Example.vcf". + + Note that binary data are not shown in the output of + printVObject. Instead, a note is made ([raw data]) to + indicate that there exists such a binary data. + +* Note on Binary Data + When the value of a property is a binary data, it is only + useful to know the size of the binary data. + + In the case of the VCard/VCalendar parser, it chooses + to represent the size information as a separate property + called VCDataSizeProp whose value is the size of the binary + data. The APIs sequence to construct the VObject subtree + of line [44] of Example.vcf is + + // VObject *vcard; + VObject *p1 = addProp(vcard,VCLogoProp); + (void) addProp(p1,VCGIFProp); + (void) addProp(p1,VCBASE64Prop); + VObject *p2 = addProp(p1,VCDataSizeProp); + (void) setVObjectLongValue(p2,1482); + setVObjectAnyValue(vcard,...pointer to binary data); + + Note the presence of VCBase64Prop will cause the + writeVObject API to output the binary data as BASE64 text. + For VCard/VCalendar application, having the VCBase64Prop + property is pratically always necessary for property with + binary data as its value. + +* Note on Quoted-Printable String + String value with embedded newline are written out as + quoted-prinatable string. It is therefore important + to mark a property with a string value that has + one or more embedded newlines, with the VCQutedPrintableProp + property. e.g. + + // VObject *root; + char *msg="To be\nor\nnot to be"; + VObject *p = addPropValue(root,VCDescriptionProp,msg); + // the following is how you mark a property with + // a property. In this case, the marker is + // VCQuotedPrintableProp + addProp(p,VCQuotedPrintableProp); + +* Note on Unicode + Although, the current parser takes ASCII text file only, + string values are all stored as Unicode in the VObject tree. + For now, when using the VObject APIs to construct a + VObject tree, one should always convert ASCII string value + to a Unicode string value: + + // VObject *root; + VObject *p = addProp(root,VCSomeProp); + setVObjectUStringZValue(p,fakeUnicode(someASCIIStringZvalue)); + + An API is provided to simplify the above process: + + addPropValue(root,VCSomeProp,someASCIIStringZValue); + + Note that someASCIISTringZValue is automatically converted to + Unicode by addPropValue API, where as, the former code + sequence do an explicit call to fakeUnicode. + + To read back the value, one should use the vObjectUStringZValue + API not vObjectStringZValue API. The value returned by the + vObjectUStringZValue API is a Unicode string. If the application + do not know how to handle Unicode string, it can use the + fakeCString API to convert it back to ASCII string (as long + as the conversion is meaningful). + + Note that fakeCString return a heap allocated memory. It is + important to call deleteStr on fakeCString return value if + it is not longer required (or there will be memory leak). + + NOTE: Unfortunately, at the point when this document is written, + there is still no consensus on how Unicode is to be handled + in the textual representation of VCard/VCalendar. So, there + is no version of writeVObject and the parser to output and + input Unicode textual representation of VCard/VCalendar. + + +Example.vcf +----------- +line +number Input Text (example.vcf) +------ ---------- +1 BEGIN:VCALENDAR +2 DCREATED:19961102T100522 +3 GEO:0,0 +4 VERSION:1.0 +5 BEGIN:VEVENT +6 DTSTART:19961103T000000 +7 DTEND:20000101T000000 +8 DESCRIPTION;QUOTED-PRINTABLE:To be =0A= +9 or =0A= +10 not to be +11 STATUS:O.K. +12 X-ACTION:No action required +13 DALARM:19961103T114500;5;3;Enjoy +14 MALARM:19970101T120000;;;johny@nowhere.com;Call Mom. +15 END:VEVENT +16 +17 BEGIN:VTODO +18 DUE:19960614T0173000 +19 DESCRIPTION:Relex. +20 END:VTODO +21 +22 END:VCALENDAR +23 +24 BEGIN:VCARD +25 N:Alden;Roland +26 FN:Roland H. Alden +27 ORG:AT&T;Versit Project Office +28 TITLE:Consultant +29 EMAIL;WORK;PREF;INTERNET:ralden@ralden.com +30 LABEL;DOM;POSTAL;PARCEL;HOME;WORK;QUOTED-PRINTABLE:Roland H. Alden=0A= +31 Suite 2208=0A= +32 One Pine Street=0A= +33 San Francisco, CA 94111 +34 LABEL;POSTAL;PARCEL;HOME;WORK;QUOTED-PRINTABLE:Roland H. Alden=0A= +35 Suite 2208=0A= +36 One Pine Street=0A= +37 San Francisco, CA 94111=0A= +38 U.S.A. +39 TEL;WORK;PREF;MSG:+1 415 296 9106 +40 TEL;WORK;FAX:+1 415 296 9016 +41 TEL;MSG;CELL:+1 415 608 5981 +42 ADR:;Suite 2208;One Pine Street;San Francisco;CA;94111;U.S.A. +43 SOUND:ROW-LAND H ALL-DIN +44 LOGO;GIF;BASE64: +45 R0lGODdhpgBOAMQAAP///+/v797e3s7Ozr29va2trZycnIyMjHt7e2NjY1JSUkJC + ... 30 lines of BASE64 data not shown here. +76 END:VCARD + + +VObject Representation of Example.vcf: +------------------------------------- +line +in +text +file VObject Tree as Printed by printVObject API +---- ------------------------------------------- +1 VCALENDAR +2 DCREATED="19961102T100522" +3 GEO="0,0" +4 VERSION="1.0" +5 VEVENT +6 DTSTART="19961103T000000" +7 DTEND="20000101T000000" +8 DESCRIPTION="To be +9 or +10 not to be" +8 QUOTED-PRINTABLE +11 STATUS="O.K." +12 X-ACTION="No action required" +13 DALARM +13 RUNTIME="19961103T114500" +13 SNOOZETIME="5" +13 REPEATCOUNT="3" +13 DISPLAYSTRING="Enjoy" +14 MALARM +14 RUNTIME="19970101T120000" +14 EMAIL="johny@nowhere.com" +14 NOTE="Call Mom" +17 VTODO +18 DUE="19960614T0173000" +19 DESCRIPTION="Relex." +24 VCARD +25 N +25 F="Alden" +25 G="Roland" +26 FN="Roland H. Alden" +27 ORG +27 ORGNAME="AT&T" +27 OUN="Versit Project Office" +28 TITLE="Consultant" +29 EMAIL="ralden@alden.com" +29 WORK +29 PREF +29 INTERNET +30 LABEL="Roland H. Alden +31 Suite 2208 +32 One Pine Street +33 San Francisco, CA 94111" +30 DOM +30 POSTAL +30 PARCEL +30 HOME +30 WORK +30 QUOTED-PRINTABLE +34 LABEL="Roland H. Alden +35 Suite 2208 +36 One Pine Street +37 San Francisco, CA 94111 +38 U.S.A." +34 POSTAL +34 PARCEL +34 HOME +34 WORK +34 QUOTED-PRINTABLE +39 TEL="+1 415 296 9106" +39 WORK +39 PREF +39 MSG +40 TEL="+1 415 296 9016" +40 WORK +40 FAX +41 TEL="+1 415 608 5981" +41 MSG +41 CELL +42 ADR +42 EXT ADD="Suite 2208" +42 STREET="One Pine Street" +42 L="San Francisco" +42 R="CA" +42 PC="94111" +42 C="U.S.A." +43 SOUND="ROW-LAND H ALL-DIN" +44 LOGO=[raw data] +44 GIF +44 BASE64 +44 DATASIZE=1482 + diff --git a/libkcal/versit/vcc.c b/libkcal/versit/vcc.c new file mode 100644 index 000000000..0dfc6bff6 --- /dev/null +++ b/libkcal/versit/vcc.c @@ -0,0 +1,2498 @@ +/* A Bison parser, made by GNU Bison 1.875. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Written by Richard Stallman by simplifying the original so called + ``semantic'' parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + EQ = 258, + COLON = 259, + DOT = 260, + SEMICOLON = 261, + SPACE = 262, + HTAB = 263, + LINESEP = 264, + NEWLINE = 265, + BEGIN_VCARD = 266, + END_VCARD = 267, + BEGIN_VCAL = 268, + END_VCAL = 269, + BEGIN_VEVENT = 270, + END_VEVENT = 271, + BEGIN_VTODO = 272, + END_VTODO = 273, + ID = 274, + STRING = 275 + }; +#endif +#define EQ 258 +#define COLON 259 +#define DOT 260 +#define SEMICOLON 261 +#define SPACE 262 +#define HTAB 263 +#define LINESEP 264 +#define NEWLINE 265 +#define BEGIN_VCARD 266 +#define END_VCARD 267 +#define BEGIN_VCAL 268 +#define END_VCAL 269 +#define BEGIN_VEVENT 270 +#define END_VEVENT 271 +#define BEGIN_VTODO 272 +#define END_VTODO 273 +#define ID 274 +#define STRING 275 + + + + +/* Copy the first part of user declarations. */ +#line 1 "vcc.y" + + +/*************************************************************************** +(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International +Business Machines Corporation and Siemens Rolm Communications Inc. + +For purposes of this license notice, the term Licensors shall mean, +collectively, Apple Computer, Inc., AT&T Corp., International +Business Machines Corporation and Siemens Rolm Communications Inc. +The term Licensor shall mean any of the Licensors. + +Subject to acceptance of the following conditions, permission is hereby +granted by Licensors without the need for written agreement and without +license or royalty fees, to use, copy, modify and distribute this +software for any purpose. + +The above copyright notice and the following four paragraphs must be +reproduced in all copies of this software and any software including +this software. + +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE +ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR +MODIFICATIONS. + +IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, +INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT +OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. + +The software is provided with RESTRICTED RIGHTS. Use, duplication, or +disclosure by the government are subject to restrictions set forth in +DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. + +***************************************************************************/ + +/* + * src: vcc.c + * doc: Parser for vCard and vCalendar. Note that this code is + * generated by a yacc parser generator. Generally it should not + * be edited by hand. The real source is vcc.y. The #line directives + * can be commented out here to make it easier to trace through + * in a debugger. However, if a bug is found it should + * be fixed in vcc.y and this file regenerated. + */ + + +/* debugging utilities */ +#if __DEBUG +#define DBG_(x) printf x +#else +#define DBG_(x) +#endif + +/**** External Functions ****/ + +/* assign local name to parser variables and functions so that + we can use more than one yacc based parser. +*/ + +#define yyparse mime_parse +#define yylex mime_lex +#define yyerror mime_error +#define yychar mime_char +/* #define p_yyval p_mime_val */ +#undef yyval +#define yyval mime_yyval +/* #define p_yylval p_mime_lval */ +#undef yylval +#define yylval mime_yylval +#define yydebug mime_debug +#define yynerrs mime_nerrs +#define yyerrflag mime_errflag +#define yyss mime_ss +#define yyssp mime_ssp +#define yyvs mime_vs +#define yyvsp mime_vsp +#define yylhs mime_lhs +#define yylen mime_len +#define yydefred mime_defred +#define yydgoto mime_dgoto +#define yysindex mime_sindex +#define yyrindex mime_rindex +#define yygindex mime_gindex +#define yytable mime_table +#define yycheck mime_check +#define yyname mime_name +#define yyrule mime_rule +#undef YYPREFIX +#define YYPREFIX "mime_" + + +#ifndef _NO_LINE_FOLDING +#define _SUPPORT_LINE_FOLDING 1 +#endif + +#include <string.h> +#if !defined(__FreeBSD__) && !defined(__APPLE__) +#include <malloc.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include "vcc.h" + +/* The following is a hack that I hope will get things compiling + * on SunOS 4.1.x systems + */ +#ifndef SEEK_SET +#define SEEK_SET 0 /* Seek from beginning of file. */ +#define SEEK_CUR 1 /* Seek from current position. */ +#define SEEK_END 2 /* Seek from end of file. */ +#endif + +/**** Types, Constants ****/ + +#define YYDEBUG 0 /* 1 to compile in some debugging code */ +#define MAXTOKEN 256 /* maximum token (line) length */ +#define YYSTACKSIZE 1000 /* ~unref ? */ +#define MAXLEVEL 10 /* max # of nested objects parseable */ + /* (includes outermost) */ + + +/**** Global Variables ****/ +int mime_lineNum, mime_numErrors; /* yyerror() can use these */ +static VObject* vObjList; +static VObject *curProp; +static VObject *curObj; +static VObject* ObjStack[MAXLEVEL]; +static int ObjStackTop; + + +/* A helpful utility for the rest of the app. */ +#if __CPLUSPLUS__ +extern "C" { +#endif + + /* static void Parse_Debug(const char *s);*/ + static void yyerror(char *s); + +#if __CPLUSPLUS__ + }; +#endif + +int yyparse(); +static int yylex(); + +static VObject* popVObject(); + + +enum LexMode { + L_NORMAL, + L_VCARD, + L_VCAL, + L_VEVENT, + L_VTODO, + L_VALUES, + L_BASE64, + L_QUOTED_PRINTABLE + }; + +/**** Private Forward Declarations ****/ +static int pushVObject(const char *prop); +static VObject* popVObject(); +char* lexDataFromBase64(); +static void lexPopMode(int top); +static int lexWithinMode(enum LexMode mode); +static void lexPushMode(enum LexMode mode); +static void enterProps(const char *s); +static void enterAttr(const char *s1, const char *s2); +/* static void enterValues(const char *value); */ +static void appendValue(const char *value); +static void mime_error_(char *s); + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) +#line 185 "vcc.y" +typedef union YYSTYPE { + char *str; + VObject *vobj; + } YYSTYPE; +/* Line 191 of yacc.c. */ +#line 300 "vcc.tab.c" +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 214 of yacc.c. */ +#line 312 "vcc.tab.c" + +#if ! defined (yyoverflow) || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC malloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined (__STDC__) || defined (__cplusplus) + typedef signed char yysigned_char; +#else + typedef short yysigned_char; +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 12 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 56 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 21 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 31 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 47 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 62 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 275 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const unsigned char yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const unsigned char yyprhs[] = +{ + 0, 0, 3, 5, 6, 10, 12, 14, 16, 17, + 22, 23, 27, 30, 32, 33, 39, 41, 42, 46, + 48, 51, 53, 56, 58, 62, 64, 65, 70, 72, + 74, 75, 76, 81, 82, 86, 89, 91, 93, 95, + 97, 98, 103, 104, 108, 109, 114, 115 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yysigned_char yyrhs[] = +{ + 22, 0, -1, 23, -1, -1, 25, 24, 23, -1, + 25, -1, 26, -1, 41, -1, -1, 11, 27, 29, + 12, -1, -1, 11, 28, 12, -1, 30, 29, -1, + 30, -1, -1, 32, 4, 31, 38, 9, -1, 1, + -1, -1, 37, 33, 34, -1, 37, -1, 35, 34, + -1, 35, -1, 6, 36, -1, 37, -1, 37, 3, + 37, -1, 19, -1, -1, 40, 6, 39, 38, -1, + 40, -1, 20, -1, -1, -1, 13, 42, 44, 14, + -1, -1, 13, 43, 14, -1, 45, 44, -1, 45, + -1, 46, -1, 49, -1, 29, -1, -1, 15, 47, + 29, 16, -1, -1, 15, 48, 16, -1, -1, 17, + 50, 29, 18, -1, -1, 17, 51, 18, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const unsigned short yyrline[] = +{ + 0, 213, 213, 217, 216, 219, 223, 224, 229, 228, + 239, 238, 250, 251, 255, 254, 264, 268, 267, 272, + 278, 279, 282, 285, 289, 296, 299, 299, 300, 304, + 306, 311, 310, 316, 315, 321, 322, 326, 327, 328, + 333, 332, 344, 343, 357, 356, 368, 367 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE +/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "EQ", "COLON", "DOT", "SEMICOLON", "SPACE", + "HTAB", "LINESEP", "NEWLINE", "BEGIN_VCARD", "END_VCARD", "BEGIN_VCAL", + "END_VCAL", "BEGIN_VEVENT", "END_VEVENT", "BEGIN_VTODO", "END_VTODO", + "ID", "STRING", "$accept", "mime", "vobjects", "@1", "vobject", "vcard", + "@2", "@3", "items", "item", "@4", "prop", "@5", "attr_params", + "attr_param", "attr", "name", "values", "@6", "value", "vcal", "@7", + "@8", "calitems", "calitem", "eventitem", "@9", "@10", "todoitem", + "@11", "@12", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const unsigned short yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const unsigned char yyr1[] = +{ + 0, 21, 22, 24, 23, 23, 25, 25, 27, 26, + 28, 26, 29, 29, 31, 30, 30, 33, 32, 32, + 34, 34, 35, 36, 36, 37, 39, 38, 38, 40, + 40, 42, 41, 43, 41, 44, 44, 45, 45, 45, + 47, 46, 48, 46, 50, 49, 51, 49 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const unsigned char yyr2[] = +{ + 0, 2, 1, 0, 3, 1, 1, 1, 0, 4, + 0, 3, 2, 1, 0, 5, 1, 0, 3, 1, + 2, 1, 2, 1, 3, 1, 0, 4, 1, 1, + 0, 0, 4, 0, 3, 2, 1, 1, 1, 1, + 0, 4, 0, 3, 0, 4, 0, 3 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const unsigned char yydefact[] = +{ + 0, 8, 31, 0, 2, 3, 6, 7, 0, 0, + 0, 0, 1, 0, 16, 25, 0, 0, 0, 17, + 11, 40, 44, 39, 0, 0, 37, 38, 34, 4, + 9, 12, 14, 0, 0, 0, 0, 0, 32, 35, + 30, 0, 18, 21, 0, 43, 0, 47, 29, 0, + 28, 22, 23, 20, 41, 45, 15, 26, 0, 30, + 24, 27 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yysigned_char yydefgoto[] = +{ + -1, 3, 4, 13, 5, 6, 8, 9, 23, 17, + 40, 18, 33, 42, 43, 51, 19, 49, 59, 50, + 7, 10, 11, 24, 25, 26, 34, 35, 27, 36, + 37 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -18 +static const yysigned_char yypact[] = +{ + -5, -10, -11, 5, -18, 10, -18, -18, 3, -1, + 12, 16, -18, -5, -18, -18, 20, 0, 29, 30, + -18, 19, 18, -18, 23, 6, -18, -18, -18, -18, + -18, -18, -18, 32, 3, 24, 3, 21, -18, -18, + 22, 25, -18, 32, 27, -18, 28, -18, -18, 36, + 41, -18, 45, -18, -18, -18, -18, -18, 25, 22, + -18, -18 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yysigned_char yypgoto[] = +{ + -18, -18, 37, -18, -18, -18, -18, -18, -8, -18, + -18, -18, -18, 8, -18, -18, -17, -7, -18, -18, + -18, -18, -18, 31, -18, -18, -18, -18, -18, -18, + -18 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -47 +static const yysigned_char yytable[] = +{ + 16, 14, -10, -33, 14, 12, 1, 14, 2, 31, + -5, 20, -13, 14, -13, -13, -13, -13, -13, 15, + -36, 21, 15, 22, 52, 15, 44, 21, 46, 22, + 28, 15, 30, 32, -19, -42, -46, 38, 41, 47, + 45, 60, 48, 54, 15, 56, 55, 57, 58, 0, + 29, 53, 61, 0, 0, 0, 39 +}; + +static const yysigned_char yycheck[] = +{ + 8, 1, 12, 14, 1, 0, 11, 1, 13, 17, + 0, 12, 12, 1, 14, 15, 16, 17, 18, 19, + 14, 15, 19, 17, 41, 19, 34, 15, 36, 17, + 14, 19, 12, 4, 4, 16, 18, 14, 6, 18, + 16, 58, 20, 16, 19, 9, 18, 6, 3, -1, + 13, 43, 59, -1, -1, -1, 25 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const unsigned char yystos[] = +{ + 0, 11, 13, 22, 23, 25, 26, 41, 27, 28, + 42, 43, 0, 24, 1, 19, 29, 30, 32, 37, + 12, 15, 17, 29, 44, 45, 46, 49, 14, 23, + 12, 29, 4, 33, 47, 48, 50, 51, 14, 44, + 31, 6, 34, 35, 29, 16, 29, 18, 20, 38, + 40, 36, 37, 34, 16, 18, 9, 6, 3, 39, + 37, 38 +}; + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up");\ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.first_line = Rhs[1].first_line; \ + Current.first_column = Rhs[1].first_column; \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +# define YYDSYMPRINT(Args) \ +do { \ + if (yydebug) \ + yysymprint Args; \ +} while (0) + +# define YYDSYMPRINTF(Title, Token, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yysymprint (stderr, \ + Token, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (cinluded). | +`------------------------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_stack_print (short *bottom, short *top) +#else +static void +yy_stack_print (bottom, top) + short *bottom; + short *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (/* Nothing. */; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_reduce_print (int yyrule) +#else +static void +yy_reduce_print (yyrule) + int yyrule; +#endif +{ + int yyi; + unsigned int yylineno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", + yyrule - 1, yylineno); + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) + YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); + YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]); +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (Rule); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YYDSYMPRINT(Args) +# define YYDSYMPRINTF(Title, Token, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +#endif /* !YYERROR_VERBOSE */ + + + +#if YYDEBUG +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) +#else +static void +yysymprint (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + if (yytype < YYNTOKENS) + { + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); +# ifdef YYPRINT + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + } + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + switch (yytype) + { + default: + break; + } + YYFPRINTF (yyoutput, ")"); +} + +#endif /* ! YYDEBUG */ +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yydestruct (int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yytype, yyvaluep) + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM); +# else +int yyparse (); +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM) +# else +int yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short yyssa[YYINITDEPTH]; + short *yyss = yyssa; + register short *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + + + +#define YYPOPSTACK (yyvsp--, yyssp--) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyoverflowlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + short *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken])); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; + + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 3: +#line 217 "vcc.y" + { addList(&vObjList, yyvsp[0].vobj); curObj = 0; ;} + break; + + case 5: +#line 220 "vcc.y" + { addList(&vObjList, yyvsp[0].vobj); curObj = 0; ;} + break; + + case 8: +#line 229 "vcc.y" + { + lexPushMode(L_VCARD); + if (!pushVObject(VCCardProp)) YYERROR; + ;} + break; + + case 9: +#line 234 "vcc.y" + { + lexPopMode(0); + yyval.vobj = popVObject(); + ;} + break; + + case 10: +#line 239 "vcc.y" + { + lexPushMode(L_VCARD); + if (!pushVObject(VCCardProp)) YYERROR; + ;} + break; + + case 11: +#line 244 "vcc.y" + { + lexPopMode(0); + yyval.vobj = popVObject(); + ;} + break; + + case 14: +#line 255 "vcc.y" + { + lexPushMode(L_VALUES); + ;} + break; + + case 15: +#line 259 "vcc.y" + { + if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE)) + lexPopMode(0); + lexPopMode(0); + ;} + break; + + case 17: +#line 268 "vcc.y" + { + enterProps(yyvsp[0].str); + ;} + break; + + case 19: +#line 273 "vcc.y" + { + enterProps(yyvsp[0].str); + ;} + break; + + case 23: +#line 286 "vcc.y" + { + enterAttr(yyvsp[0].str,0); + ;} + break; + + case 24: +#line 290 "vcc.y" + { + enterAttr(yyvsp[-2].str,yyvsp[0].str); + + ;} + break; + + case 26: +#line 299 "vcc.y" + { appendValue(yyvsp[-1].str); ;} + break; + + case 28: +#line 301 "vcc.y" + { appendValue(yyvsp[0].str); ;} + break; + + case 30: +#line 306 "vcc.y" + { yyval.str = 0; ;} + break; + + case 31: +#line 311 "vcc.y" + { if (!pushVObject(VCCalProp)) YYERROR; ;} + break; + + case 32: +#line 314 "vcc.y" + { yyval.vobj = popVObject(); ;} + break; + + case 33: +#line 316 "vcc.y" + { if (!pushVObject(VCCalProp)) YYERROR; ;} + break; + + case 34: +#line 318 "vcc.y" + { yyval.vobj = popVObject(); ;} + break; + + case 40: +#line 333 "vcc.y" + { + lexPushMode(L_VEVENT); + if (!pushVObject(VCEventProp)) YYERROR; + ;} + break; + + case 41: +#line 339 "vcc.y" + { + lexPopMode(0); + popVObject(); + ;} + break; + + case 42: +#line 344 "vcc.y" + { + lexPushMode(L_VEVENT); + if (!pushVObject(VCEventProp)) YYERROR; + ;} + break; + + case 43: +#line 349 "vcc.y" + { + lexPopMode(0); + popVObject(); + ;} + break; + + case 44: +#line 357 "vcc.y" + { + lexPushMode(L_VTODO); + if (!pushVObject(VCTodoProp)) YYERROR; + ;} + break; + + case 45: +#line 363 "vcc.y" + { + lexPopMode(0); + popVObject(); + ;} + break; + + case 46: +#line 368 "vcc.y" + { + lexPushMode(L_VTODO); + if (!pushVObject(VCTodoProp)) YYERROR; + ;} + break; + + case 47: +#line 373 "vcc.y" + { + lexPopMode(0); + popVObject(); + ;} + break; + + + } + +/* Line 991 of yacc.c. */ +#line 1429 "vcc.tab.c" + + yyvsp -= yylen; + yyssp -= yylen; + + + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (YYPACT_NINF < yyn && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + int yytype = YYTRANSLATE (yychar); + char *yymsg; + int yyx, yycount; + + yycount = 0; + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + yysize += yystrlen (yytname[yyx]) + 15, yycount++; + yysize += yystrlen ("syntax error, unexpected ") + 1; + yysize += yystrlen (yytname[yytype]); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); + yyp = yystpcpy (yyp, yytname[yytype]); + + if (yycount < 5) + { + yycount = 0; + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); + yyx++) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + const char *yyq = ! yycount ? ", expecting " : " or "; + yyp = yystpcpy (yyp, yyq); + yyp = yystpcpy (yyp, yytname[yyx]); + yycount++; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("syntax error; also virtual memory exhausted"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror ("syntax error"); + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* Return failure if at end of input. */ + if (yychar == YYEOF) + { + /* Pop the error token. */ + YYPOPSTACK; + /* Pop the rest of the stack. */ + while (yyss < yyssp) + { + YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); + yydestruct (yystos[*yyssp], yyvsp); + YYPOPSTACK; + } + YYABORT; + } + + YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc); + yydestruct (yytoken, &yylval); + yychar = YYEMPTY; + + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab2; + + +/*----------------------------------------------------. +| yyerrlab1 -- error raised explicitly by an action. | +`----------------------------------------------------*/ +yyerrlab1: + + /* Suppress GCC warning that yyerrlab1 is unused when no action + invokes YYERROR. */ +#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__) \ + && !defined __cplusplus + __attribute__ ((__unused__)) +#endif + + + goto yyerrlab2; + + +/*---------------------------------------------------------------. +| yyerrlab2 -- pop states until the error token can be shifted. | +`---------------------------------------------------------------*/ +yyerrlab2: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); + yydestruct (yystos[yystate], yyvsp); + yyvsp--; + yystate = *--yyssp; + + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++yyvsp = yylval; + + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*----------------------------------------------. +| yyoverflowlab -- parser overflow comes here. | +`----------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} + + +#line 379 "vcc.y" + +/****************************************************************************/ +static int pushVObject(const char *prop) + { + VObject *newObj; + if (ObjStackTop == MAXLEVEL) + return FALSE; + + ObjStack[++ObjStackTop] = curObj; + + if (curObj) { + newObj = addProp(curObj,prop); + curObj = newObj; + } + else + curObj = newVObject(prop); + + return TRUE; + } + + +/****************************************************************************/ +/* This pops the recently built vCard off the stack and returns it. */ +static VObject* popVObject() + { + VObject *oldObj; + if (ObjStackTop < 0) { + yyerror("pop on empty Object Stack\n"); + return 0; + } + oldObj = curObj; + curObj = ObjStack[ObjStackTop--]; + + return oldObj; + } + + +/* static void enterValues(const char *value) */ +/* { */ +/* if (fieldedProp && *fieldedProp) { */ +/* if (value) { */ +/* addPropValue(curProp,*fieldedProp,value); */ +/* } */ + /* else this field is empty, advance to next field */ +/* fieldedProp++; */ +/* } */ +/* else { */ +/* if (value) { */ +/* setVObjectUStringZValue_(curProp,fakeUnicode(value,0)); */ +/* } */ +/* } */ +/* deleteStr(value); */ +/* } */ + +static void appendValue(const char *value) +{ + char *p1, *p2; + wchar_t *p3; + int i; + + if (fieldedProp && *fieldedProp) { + if (value) { + addPropValue(curProp, *fieldedProp, value); + } + /* else this field is empty, advance to next field */ + fieldedProp++; + } else { + if (value) { + if (vObjectUStringZValue(curProp)) { + p1 = fakeCString(vObjectUStringZValue(curProp)); + p2 = malloc(sizeof(char *) * (strlen(p1)+strlen(value)+1)); + strcpy(p2, p1); + deleteStr(p1); + + i = strlen(p2); + p2[i] = ','; + p2[i+1] = '\0'; + p2 = strcat(p2, value); + p3 = (wchar_t *) vObjectUStringZValue(curProp); + free(p3); + setVObjectUStringZValue_(curProp,fakeUnicode(p2,0)); + deleteStr(p2); + } else { + setVObjectUStringZValue_(curProp,fakeUnicode(value,0)); + } + } + } + deleteStr(value); +} + + +static void enterProps(const char *s) + { + curProp = addGroup(curObj,s); + deleteStr(s); + } + +static void enterAttr(const char *s1, const char *s2) + { + const char *p1=0L, *p2=0L; + p1 = lookupProp_(s1); + if (s2) { + VObject *a; + p2 = lookupProp_(s2); + a = addProp(curProp,p1); + setVObjectStringZValue(a,p2); + } + else + addProp(curProp,p1); + if (strcasecmp(p1,VCBase64Prop) == 0 || (s2 && strcasecmp(p2,VCBase64Prop)==0)) + lexPushMode(L_BASE64); + else if (strcasecmp(p1,VCQuotedPrintableProp) == 0 + || (s2 && strcasecmp(p2,VCQuotedPrintableProp)==0)) + lexPushMode(L_QUOTED_PRINTABLE); + deleteStr(s1); deleteStr(s2); + } + + +#define MAX_LEX_LOOKAHEAD_0 32 +#define MAX_LEX_LOOKAHEAD 64 +#define MAX_LEX_MODE_STACK_SIZE 10 +#define LEXMODE() (lexBuf.lexModeStack[lexBuf.lexModeStackTop]) + +struct LexBuf { + /* input */ + FILE *inputFile; + char *inputString; + unsigned long curPos; + unsigned long inputLen; + /* lookahead buffer */ + /* -- lookahead buffer is short instead of char so that EOF + / can be represented correctly. + */ + unsigned long len; + short buf[MAX_LEX_LOOKAHEAD]; + unsigned long getPtr; + /* context stack */ + unsigned long lexModeStackTop; + enum LexMode lexModeStack[MAX_LEX_MODE_STACK_SIZE]; + /* token buffer */ + unsigned long maxToken; + char *strs; + unsigned long strsLen; + } lexBuf; + +static void lexPushMode(enum LexMode mode) + { + if (lexBuf.lexModeStackTop == (MAX_LEX_MODE_STACK_SIZE-1)) + yyerror("lexical context stack overflow"); + else { + lexBuf.lexModeStack[++lexBuf.lexModeStackTop] = mode; + } + } + +static void lexPopMode(int top) + { + /* special case of pop for ease of error recovery -- this + version will never underflow */ + if (top) + lexBuf.lexModeStackTop = 0; + else + if (lexBuf.lexModeStackTop > 0) lexBuf.lexModeStackTop--; + } + +static int lexWithinMode(enum LexMode mode) { + unsigned long i; + for (i=0;i<lexBuf.lexModeStackTop;i++) + if (mode == lexBuf.lexModeStack[i]) return 1; + return 0; + } + +static int lexGetc_() + { + /* get next char from input, no buffering. */ + if (lexBuf.curPos == lexBuf.inputLen) + return EOF; + else if (lexBuf.inputString) + return *(lexBuf.inputString + lexBuf.curPos++); + else { + if (!feof(lexBuf.inputFile)) + return fgetc(lexBuf.inputFile); + else + return EOF; + } + } + +static int lexGeta() + { + ++lexBuf.len; + return (lexBuf.buf[lexBuf.getPtr] = lexGetc_()); + } + +static int lexGeta_(int i) + { + ++lexBuf.len; + return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_()); + } + +static void lexSkipLookahead() { + if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) { + /* don't skip EOF. */ + lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD; + lexBuf.len--; + } + } + +static int lexLookahead() { + int c = (lexBuf.len)? + lexBuf.buf[lexBuf.getPtr]: + lexGeta(); + /* do the \r\n -> \n or \r -> \n translation here */ + if (c == '\r') { + int a = (lexBuf.len>1)? + lexBuf.buf[(lexBuf.getPtr+1)%MAX_LEX_LOOKAHEAD]: + lexGeta_(1); + if (a == '\n') { + lexSkipLookahead(); + } + lexBuf.buf[lexBuf.getPtr] = c = '\n'; + } + else if (c == '\n') { + int a; + if (lexBuf.len > 1) + a = lexBuf.buf[lexBuf.getPtr]; + else + a = lexGeta_(1); + if (a == '\r') { + lexSkipLookahead(); + } + lexBuf.buf[lexBuf.getPtr] = '\n'; + } + return c; + } + +static int lexGetc() { + int c = lexLookahead(); + if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) { + /* EOF will remain in lookahead buffer */ + lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD; + lexBuf.len--; + } + return c; + } + +static void lexSkipLookaheadWord() { + if (lexBuf.strsLen <= lexBuf.len) { + lexBuf.len -= lexBuf.strsLen; + lexBuf.getPtr = (lexBuf.getPtr + lexBuf.strsLen) % MAX_LEX_LOOKAHEAD; + } + } + +static void lexClearToken() + { + lexBuf.strsLen = 0; + } + +static void lexAppendc(int c) + { + /* not sure if I am doing this right to fix purify report -- PGB */ + lexBuf.strs = (char *) realloc(lexBuf.strs, (size_t) lexBuf.strsLen + 1); + lexBuf.strs[lexBuf.strsLen] = c; + /* append up to zero termination */ + if (c == 0) return; + lexBuf.strsLen++; + if (lexBuf.strsLen > lexBuf.maxToken) { + /* double the token string size */ + lexBuf.maxToken <<= 1; + lexBuf.strs = (char*) realloc(lexBuf.strs,(size_t)lexBuf.maxToken); + } + } + +static char* lexStr() { + return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1); + } + +static void lexSkipWhite() { + int c = lexLookahead(); + while (c == ' ' || c == '\t') { + lexSkipLookahead(); + c = lexLookahead(); + } + } + +static char* lexGetWord() { + int c; + lexSkipWhite(); + lexClearToken(); + c = lexLookahead(); + /* some "words" have a space in them, like "NEEDS ACTION". + this may be an oversight of the spec, but it is true nevertheless. + while (c != EOF && !strchr("\t\n ;:=",c)) { */ + while (c != EOF && !strchr("\n;:=",c)) { + lexAppendc(c); + lexSkipLookahead(); + c = lexLookahead(); + } + lexAppendc(0); + return lexStr(); + } + +void lexPushLookahead(char *s, int len) { + int putptr; + if (len == 0) len = strlen(s); + putptr = (int)lexBuf.getPtr - len; + /* this function assumes that length of word to push back + / is not greater than MAX_LEX_LOOKAHEAD. + */ + if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD; + lexBuf.getPtr = putptr; + while (*s) { + lexBuf.buf[putptr] = *s++; + putptr = (putptr + 1) % MAX_LEX_LOOKAHEAD; + } + lexBuf.len += len; + } + +static void lexPushLookaheadc(int c) { + int putptr; + /* can't putback EOF, because it never leaves lookahead buffer */ + if (c == EOF) return; + putptr = (int)lexBuf.getPtr - 1; + if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD; + lexBuf.getPtr = putptr; + lexBuf.buf[putptr] = c; + lexBuf.len += 1; + } + +static char* lexLookaheadWord() { + /* this function can lookahead word with max size of MAX_LEX_LOOKAHEAD_0 + / and thing bigger than that will stop the lookahead and return 0; + / leading white spaces are not recoverable. + */ + int c; + int len = 0; + int curgetptr = 0; + lexSkipWhite(); + lexClearToken(); + curgetptr = (int)lexBuf.getPtr; /* remember! */ + while (len < (MAX_LEX_LOOKAHEAD_0)) { + c = lexGetc(); + len++; + if (c == EOF || strchr("\t\n ;:=", c)) { + lexAppendc(0); + /* restore lookahead buf. */ + lexBuf.len += len; + lexBuf.getPtr = curgetptr; + return lexStr(); + } + else + lexAppendc(c); + } + lexBuf.len += len; /* char that has been moved to lookahead buffer */ + lexBuf.getPtr = curgetptr; + return 0; + } + +#ifdef _SUPPORT_LINE_FOLDING +static void handleMoreRFC822LineBreak(int c) { + /* suport RFC 822 line break in cases like + * ADR: foo; + * morefoo; + * more foo; + */ + if (c == ';') { + int a; + lexSkipLookahead(); + /* skip white spaces */ + a = lexLookahead(); + while (a == ' ' || a == '\t') { + lexSkipLookahead(); + a = lexLookahead(); + } + if (a == '\n') { + lexSkipLookahead(); + a = lexLookahead(); + if (a == ' ' || a == '\t') { + /* continuation, throw away all the \n and spaces read so + * far + */ + lexSkipWhite(); + lexPushLookaheadc(';'); + } + else { + lexPushLookaheadc('\n'); + lexPushLookaheadc(';'); + } + } + else { + lexPushLookaheadc(';'); + } + } + } + +static char* lexGet1Value() { + int c; + lexSkipWhite(); + c = lexLookahead(); + lexClearToken(); + while (c != EOF && c != ';') { + if (c == '\n') { + int a; + lexSkipLookahead(); + a = lexLookahead(); + if (a == ' ' || a == '\t') { + lexAppendc(' '); + lexSkipLookahead(); + } + else { + lexPushLookaheadc('\n'); + break; + } + } + else { + lexAppendc(c); + lexSkipLookahead(); + } + c = lexLookahead(); + } + lexAppendc(0); + handleMoreRFC822LineBreak(c); + return c==EOF?0:lexStr(); + } +#endif + +char* lexGetStrUntil(char *termset) { + int c = lexLookahead(); + lexClearToken(); + while (c != EOF && !strchr(termset,c)) { + lexAppendc(c); + lexSkipLookahead(); + c = lexLookahead(); + } + lexAppendc(0); + return c==EOF?0:lexStr(); + } + +static int match_begin_name(int end) { + char *n = lexLookaheadWord(); + int token = ID; + if (n) { + if (!strcasecmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD; + else if (!strcasecmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL; + else if (!strcasecmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT; + else if (!strcasecmp(n,"vtodo")) token = end?END_VTODO:BEGIN_VTODO; + deleteStr(n); + return token; + } + return 0; + } + + +void initLex(const char *inputstring, unsigned long inputlen, FILE *inputfile) + { + /* initialize lex mode stack */ + lexBuf.lexModeStack[lexBuf.lexModeStackTop=0] = L_NORMAL; + + /* iniatialize lex buffer. */ + lexBuf.inputString = (char*) inputstring; + lexBuf.inputLen = inputlen; + lexBuf.curPos = 0; + lexBuf.inputFile = inputfile; + + lexBuf.len = 0; + lexBuf.getPtr = 0; + + lexBuf.maxToken = MAXTOKEN; + lexBuf.strs = (char*)malloc(MAXTOKEN); + lexBuf.strsLen = 0; + + } + +static void finiLex() { + free(lexBuf.strs); + } + + +/****************************************************************************/ +/* This parses and converts the base64 format for binary encoding into + * a decoded buffer (allocated with new). See RFC 1521. + */ +static char * lexGetDataFromBase64() + { + unsigned long bytesLen = 0, bytesMax = 0; + int quadIx = 0, pad = 0; + unsigned long trip = 0; + unsigned char b; + int c; + unsigned char *bytes = NULL; + unsigned char *oldBytes = NULL; + + DBG_(("db: lexGetDataFromBase64\n")); + while (1) { + c = lexGetc(); + if (c == '\n') { + ++mime_lineNum; + if (lexLookahead() == '\n') { + /* a '\n' character by itself means end of data */ + break; + } + else continue; /* ignore '\n' */ + } + else { + if ((c >= 'A') && (c <= 'Z')) + b = (unsigned char)(c - 'A'); + else if ((c >= 'a') && (c <= 'z')) + b = (unsigned char)(c - 'a') + 26; + else if ((c >= '0') && (c <= '9')) + b = (unsigned char)(c - '0') + 52; + else if (c == '+') + b = 62; + else if (c == '/') + b = 63; + else if (c == '=') { + b = 0; + pad++; + } else if ((c == ' ') || (c == '\t')) { + continue; + } else { /* error condition */ + if (bytes) free(bytes); + else if (oldBytes) free(oldBytes); + /* error recovery: skip until 2 adjacent newlines. */ + DBG_(("db: invalid character 0x%x '%c'\n", c,c)); + if (c != EOF) { + c = lexGetc(); + while (c != EOF) { + if (c == '\n' && lexLookahead() == '\n') { + ++mime_lineNum; + break; + } + c = lexGetc(); + } + } + return NULL; + } + trip = (trip << 6) | b; + if (++quadIx == 4) { + unsigned char outBytes[3]; + int numOut; + int i; + for (i = 0; i < 3; i++) { + outBytes[2-i] = (unsigned char)(trip & 0xFF); + trip >>= 8; + } + numOut = 3 - pad; + if (bytesLen + numOut > bytesMax) { + if (!bytes) { + bytesMax = 1024; + bytes = (unsigned char*)malloc((size_t)bytesMax); + } + else { + bytesMax <<= 2; + oldBytes = bytes; + bytes = (unsigned char*)realloc(bytes,(size_t)bytesMax); + } + if (bytes == 0) { + mime_error("out of memory while processing BASE64 data\n"); + } + } + if (bytes) { + memcpy(bytes + bytesLen, outBytes, numOut); + bytesLen += numOut; + } + trip = 0; + quadIx = 0; + } + } + } /* while */ + DBG_(("db: bytesLen = %d\n", bytesLen)); + /* kludge: all this won't be necessary if we have tree form + representation */ + if (bytes) { + setValueWithSize(curProp,bytes,(unsigned int)bytesLen); + free(bytes); + } + else if (oldBytes) { + setValueWithSize(curProp,oldBytes,(unsigned int)bytesLen); + free(oldBytes); + } + return 0; + } + +static int match_begin_end_name(int end) { + int token; + lexSkipWhite(); + if (lexLookahead() != ':') return ID; + lexSkipLookahead(); + lexSkipWhite(); + token = match_begin_name(end); + if (token == ID) { + lexPushLookaheadc(':'); + DBG_(("db: ID '%s'\n", yylval.str)); + return ID; + } + else if (token != 0) { + lexSkipLookaheadWord(); + deleteStr(yylval.str); + DBG_(("db: begin/end %d\n", token)); + return token; + } + return 0; + } + +static char* lexGetQuotedPrintable() + { + char cur; + + lexClearToken(); + do { + cur = lexGetc(); + switch (cur) { + case '=': { + int c = 0; + int next[2]; + int i; + for (i = 0; i < 2; i++) { + next[i] = lexGetc(); + if (next[i] >= '0' && next[i] <= '9') + c = c * 16 + next[i] - '0'; + else if (next[i] >= 'A' && next[i] <= 'F') + c = c * 16 + next[i] - 'A' + 10; + else + break; + } + if (i == 0) { + /* single '=' follow by LINESEP is continuation sign? */ + if (next[0] == '\n') { + ++mime_lineNum; + } + else { + lexPushLookaheadc('='); + goto EndString; + } + } + else if (i == 1) { + lexPushLookaheadc(next[1]); + lexPushLookaheadc(next[0]); + lexAppendc('='); + } else { + lexAppendc(c); + } + break; + } /* '=' */ + case '\n': { + lexPushLookaheadc('\n'); + goto EndString; + } + case (char)EOF: + break; + default: + lexAppendc(cur); + break; + } /* switch */ + } while (cur != (char)EOF); + +EndString: + lexAppendc(0); + return lexStr(); + } /* LexQuotedPrintable */ + +static int yylex() { + + int lexmode = LEXMODE(); + if (lexmode == L_VALUES) { + int c = lexGetc(); + if (c == ';') { + DBG_(("db: SEMICOLON\n")); + lexPushLookaheadc(c); + handleMoreRFC822LineBreak(c); + lexSkipLookahead(); + return SEMICOLON; + } + else if (strchr("\n",c)) { + ++mime_lineNum; + /* consume all line separator(s) adjacent to each other */ + c = lexLookahead(); + while (strchr("\n",c)) { + lexSkipLookahead(); + c = lexLookahead(); + ++mime_lineNum; + } + DBG_(("db: LINESEP\n")); + return LINESEP; + } + else { + char *p = 0; + lexPushLookaheadc(c); + if (lexWithinMode(L_BASE64)) { + /* get each char and convert to bin on the fly... */ + p = lexGetDataFromBase64(); + yylval.str = p; + return STRING; + } + else if (lexWithinMode(L_QUOTED_PRINTABLE)) { + p = lexGetQuotedPrintable(); + } + else { +#ifdef _SUPPORT_LINE_FOLDING + p = lexGet1Value(); +#else + p = lexGetStrUntil(";\n"); +#endif + } + if (p) { + DBG_(("db: STRING: '%s'\n", p)); + yylval.str = p; + return STRING; + } + else return 0; + } + } + else { + /* normal mode */ + while (1) { + int c = lexGetc(); + switch(c) { + case ':': { + /* consume all line separator(s) adjacent to each other */ + /* ignoring linesep immediately after colon. */ + c = lexLookahead(); + while (strchr("\n",c)) { + lexSkipLookahead(); + c = lexLookahead(); + ++mime_lineNum; + } + DBG_(("db: COLON\n")); + return COLON; + } + case ';': + DBG_(("db: SEMICOLON\n")); + return SEMICOLON; + case '=': + DBG_(("db: EQ\n")); + return EQ; + /* ignore tabs/newlines in this mode. We can't ignore + * spaces, because values like NEEDS ACTION have a space. */ + case '\t': continue; + case '\n': { + ++mime_lineNum; + continue; + } + case EOF: return 0; + break; + default: { + lexPushLookaheadc(c); + if (isalpha(c) || c == ' ') { + char *t = lexGetWord(); + yylval.str = t; + if (!strcasecmp(t, "begin")) { + return match_begin_end_name(0); + } + else if (!strcasecmp(t,"end")) { + return match_begin_end_name(1); + } + else { + DBG_(("db: ID '%s'\n", t)); + return ID; + } + } + else { + /* unknown token */ + return 0; + } + break; + } + } + } + } + return 0; + } + + +/***************************************************************************/ +/*** Public Functions ****/ +/***************************************************************************/ + +static VObject* Parse_MIMEHelper() + { + ObjStackTop = -1; + mime_numErrors = 0; + mime_lineNum = 1; + vObjList = 0; + curObj = 0; + + if (yyparse() != 0) + return 0; + + finiLex(); + return vObjList; + } + +/****************************************************************************/ +VObject* Parse_MIME(const char *input, unsigned long len) + { + initLex(input, len, 0); + return Parse_MIMEHelper(); + } + + +VObject* Parse_MIME_FromFile(FILE *file) + { + VObject *result; + long startPos; + + initLex(0,(unsigned long)-1,file); + startPos = ftell(file); + if (!(result = Parse_MIMEHelper())) { + fseek(file,startPos,SEEK_SET); + } + return result; + } + +VObject* Parse_MIME_FromFileName(const char *fname) + { + FILE *fp = fopen(fname,"r"); + if (fp) { + VObject* o = Parse_MIME_FromFile(fp); + fclose(fp); + return o; + } + else { + char msg[255]; + snprintf(msg, sizeof(msg), "can't open file '%s' for reading\n", fname); + mime_error_(msg); + return 0; + } + } + +/****************************************************************************/ +void YYDebug(const char *s) +{ + Parse_Debug(s); +} + + +static MimeErrorHandler mimeErrorHandler; + +void registerMimeErrorHandler(MimeErrorHandler me) + { + mimeErrorHandler = me; + } + +static void mime_error(char *s) + { + char msg[256]; + if (mimeErrorHandler) { + snprintf(msg, sizeof(msg), "%s at line %d", s, mime_lineNum); + mimeErrorHandler(msg); + } + } + +static void mime_error_(char *s) + { + if (mimeErrorHandler) { + mimeErrorHandler(s); + } + } + + + diff --git a/libkcal/versit/vcc.h b/libkcal/versit/vcc.h new file mode 100644 index 000000000..03886d16d --- /dev/null +++ b/libkcal/versit/vcc.h @@ -0,0 +1,76 @@ +/*************************************************************************** +(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International +Business Machines Corporation and Siemens Rolm Communications Inc. + +For purposes of this license notice, the term Licensors shall mean, +collectively, Apple Computer, Inc., AT&T Corp., International +Business Machines Corporation and Siemens Rolm Communications Inc. +The term Licensor shall mean any of the Licensors. + +Subject to acceptance of the following conditions, permission is hereby +granted by Licensors without the need for written agreement and without +license or royalty fees, to use, copy, modify and distribute this +software for any purpose. + +The above copyright notice and the following four paragraphs must be +reproduced in all copies of this software and any software including +this software. + +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE +ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR +MODIFICATIONS. + +IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, +INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT +OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. + +The software is provided with RESTRICTED RIGHTS. Use, duplication, or +disclosure by the government are subject to restrictions set forth in +DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. + +***************************************************************************/ + +#ifndef __VCC_H__ +#define __VCC_H__ 1 + +#include "vobject.h" + + +#if defined(__CPLUSPLUS__) || defined(__cplusplus) +extern "C" { +#endif + +typedef void (*MimeErrorHandler)(char *); + +extern void registerMimeErrorHandler(MimeErrorHandler); + +extern VObject* Parse_MIME(const char *input, unsigned long len); +extern VObject* Parse_MIME_FromFileName(const char* fname); + + +/* NOTE regarding Parse_MIME_FromFile +The function below, Parse_MIME_FromFile, come in two flavors, +neither of which is exported from the DLL. Each version takes +a CFile or FILE* as a parameter, neither of which can be +passed across a DLL interface (at least that is my experience). +If you are linking this code into your build directly then +you may find them a more convenient API that the other flavors +that take a file name. If you use them with the DLL LIB you +will get a link error. +*/ + + +extern VObject* Parse_MIME_FromFile(FILE *file); + +#if defined(__CPLUSPLUS__) || defined(__cplusplus) +} +#endif + +#endif /* __VCC_H__ */ + diff --git a/libkcal/versit/vcc.y b/libkcal/versit/vcc.y new file mode 100644 index 000000000..fbfee0f6e --- /dev/null +++ b/libkcal/versit/vcc.y @@ -0,0 +1,1232 @@ +%{ + +/*************************************************************************** +(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International +Business Machines Corporation and Siemens Rolm Communications Inc. + +For purposes of this license notice, the term Licensors shall mean, +collectively, Apple Computer, Inc., AT&T Corp., International +Business Machines Corporation and Siemens Rolm Communications Inc. +The term Licensor shall mean any of the Licensors. + +Subject to acceptance of the following conditions, permission is hereby +granted by Licensors without the need for written agreement and without +license or royalty fees, to use, copy, modify and distribute this +software for any purpose. + +The above copyright notice and the following four paragraphs must be +reproduced in all copies of this software and any software including +this software. + +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE +ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR +MODIFICATIONS. + +IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, +INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT +OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. + +The software is provided with RESTRICTED RIGHTS. Use, duplication, or +disclosure by the government are subject to restrictions set forth in +DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. + +***************************************************************************/ + +/* + * src: vcc.c + * doc: Parser for vCard and vCalendar. Note that this code is + * generated by a yacc parser generator. Generally it should not + * be edited by hand. The real source is vcc.y. The #line directives + * can be commented out here to make it easier to trace through + * in a debugger. However, if a bug is found it should + * be fixed in vcc.y and this file regenerated. + */ + + +/* debugging utilities */ +#if __DEBUG +#define DBG_(x) printf x +#else +#define DBG_(x) +#endif + +/**** External Functions ****/ + +/* assign local name to parser variables and functions so that + we can use more than one yacc based parser. +*/ + +#define yyparse mime_parse +#define yylex mime_lex +#define yyerror mime_error +#define yychar mime_char +/* #define p_yyval p_mime_val */ +#undef yyval +#define yyval mime_yyval +/* #define p_yylval p_mime_lval */ +#undef yylval +#define yylval mime_yylval +#define yydebug mime_debug +#define yynerrs mime_nerrs +#define yyerrflag mime_errflag +#define yyss mime_ss +#define yyssp mime_ssp +#define yyvs mime_vs +#define yyvsp mime_vsp +#define yylhs mime_lhs +#define yylen mime_len +#define yydefred mime_defred +#define yydgoto mime_dgoto +#define yysindex mime_sindex +#define yyrindex mime_rindex +#define yygindex mime_gindex +#define yytable mime_table +#define yycheck mime_check +#define yyname mime_name +#define yyrule mime_rule +#undef YYPREFIX +#define YYPREFIX "mime_" + + +#ifndef _NO_LINE_FOLDING +#define _SUPPORT_LINE_FOLDING 1 +#endif + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include "vcc.h" + +/* The following is a hack that I hope will get things compiling + * on SunOS 4.1.x systems + */ +#ifndef SEEK_SET +#define SEEK_SET 0 /* Seek from beginning of file. */ +#define SEEK_CUR 1 /* Seek from current position. */ +#define SEEK_END 2 /* Seek from end of file. */ +#endif + +/**** Types, Constants ****/ + +#define YYDEBUG 0 /* 1 to compile in some debugging code */ +#define MAXTOKEN 256 /* maximum token (line) length */ +#define YYSTACKSIZE 1000 /* ~unref ? */ +#define MAXLEVEL 10 /* max # of nested objects parseable */ + /* (includes outermost) */ + + +/**** Global Variables ****/ +int mime_lineNum, mime_numErrors; /* yyerror() can use these */ +static VObject* vObjList; +static VObject *curProp; +static VObject *curObj; +static VObject* ObjStack[MAXLEVEL]; +static int ObjStackTop; + + +/* A helpful utility for the rest of the app. */ +#if __CPLUSPLUS__ +extern "C" { +#endif + + /* static void Parse_Debug(const char *s);*/ + static void yyerror(char *s); + +#if __CPLUSPLUS__ + }; +#endif + +int yyparse(); +static int yylex(); + +static VObject* popVObject(); + + +enum LexMode { + L_NORMAL, + L_VCARD, + L_VCAL, + L_VEVENT, + L_VTODO, + L_VALUES, + L_BASE64, + L_QUOTED_PRINTABLE + }; + +/**** Private Forward Declarations ****/ +static int pushVObject(const char *prop); +static VObject* popVObject(); +char* lexDataFromBase64(); +static void lexPopMode(int top); +static int lexWithinMode(enum LexMode mode); +static void lexPushMode(enum LexMode mode); +static void enterProps(const char *s); +static void enterAttr(const char *s1, const char *s2); +/* static void enterValues(const char *value); */ +static void appendValue(const char *value); +static void mime_error_(char *s); + +%} + +/***************************************************************************/ +/*** The grammar ****/ +/***************************************************************************/ + +%union { + char *str; + VObject *vobj; + } + +%token + EQ COLON DOT SEMICOLON SPACE HTAB LINESEP NEWLINE + BEGIN_VCARD END_VCARD BEGIN_VCAL END_VCAL + BEGIN_VEVENT END_VEVENT BEGIN_VTODO END_VTODO + ID + +/* + * NEWLINE is the token that would occur outside a vCard, + * while LINESEP is the token that would occur inside a vCard. + */ + +%token <str> + STRING ID + +%type <str> name value + +%type <vobj> vcard vcal vobject + +%start mime + +%% + + +mime: vobjects + ; + +vobjects: vobject + { addList(&vObjList, $1); curObj = 0; } + vobjects + | vobject + { addList(&vObjList, $1); curObj = 0; } + ; + +vobject: vcard + | vcal + ; + +vcard: + BEGIN_VCARD + { + lexPushMode(L_VCARD); + if (!pushVObject(VCCardProp)) YYERROR; + } + items END_VCARD + { + lexPopMode(0); + $$ = popVObject(); + } + | BEGIN_VCARD + { + lexPushMode(L_VCARD); + if (!pushVObject(VCCardProp)) YYERROR; + } + END_VCARD + { + lexPopMode(0); + $$ = popVObject(); + } + ; + +items: item items + | item + ; + +item: prop COLON + { + lexPushMode(L_VALUES); + } + values LINESEP + { + if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE)) + lexPopMode(0); + lexPopMode(0); + } + | error + ; + +prop: name + { + enterProps($1); + } + attr_params + | name + { + enterProps($1); + } + ; + +attr_params: attr_param attr_params + | attr_param + ; + +attr_param: SEMICOLON attr + ; + +attr: name + { + enterAttr($1,0); + } + | name EQ name + { + enterAttr($1,$3); + + } + ; + +name: ID + ; + +values: value SEMICOLON { appendValue($1); } values + | value + { appendValue($1); } + ; + +value: STRING + | + { $$ = 0; } + ; + +vcal: + BEGIN_VCAL + { if (!pushVObject(VCCalProp)) YYERROR; } + calitems + END_VCAL + { $$ = popVObject(); } + | BEGIN_VCAL + { if (!pushVObject(VCCalProp)) YYERROR; } + END_VCAL + { $$ = popVObject(); } + ; + +calitems: calitem calitems + | calitem + ; + +calitem: + eventitem + | todoitem + | items + ; + +eventitem: + BEGIN_VEVENT + { + lexPushMode(L_VEVENT); + if (!pushVObject(VCEventProp)) YYERROR; + } + items + END_VEVENT + { + lexPopMode(0); + popVObject(); + } + | BEGIN_VEVENT + { + lexPushMode(L_VEVENT); + if (!pushVObject(VCEventProp)) YYERROR; + } + END_VEVENT + { + lexPopMode(0); + popVObject(); + } + ; + +todoitem: + BEGIN_VTODO + { + lexPushMode(L_VTODO); + if (!pushVObject(VCTodoProp)) YYERROR; + } + items + END_VTODO + { + lexPopMode(0); + popVObject(); + } + | BEGIN_VTODO + { + lexPushMode(L_VTODO); + if (!pushVObject(VCTodoProp)) YYERROR; + } + END_VTODO + { + lexPopMode(0); + popVObject(); + } + ; + +%% +/****************************************************************************/ +static int pushVObject(const char *prop) + { + VObject *newObj; + if (ObjStackTop == MAXLEVEL) + return FALSE; + + ObjStack[++ObjStackTop] = curObj; + + if (curObj) { + newObj = addProp(curObj,prop); + curObj = newObj; + } + else + curObj = newVObject(prop); + + return TRUE; + } + + +/****************************************************************************/ +/* This pops the recently built vCard off the stack and returns it. */ +static VObject* popVObject() + { + VObject *oldObj; + if (ObjStackTop < 0) { + yyerror("pop on empty Object Stack\n"); + return 0; + } + oldObj = curObj; + curObj = ObjStack[ObjStackTop--]; + + return oldObj; + } + + +/* static void enterValues(const char *value) */ +/* { */ +/* if (fieldedProp && *fieldedProp) { */ +/* if (value) { */ +/* addPropValue(curProp,*fieldedProp,value); */ +/* } */ + /* else this field is empty, advance to next field */ +/* fieldedProp++; */ +/* } */ +/* else { */ +/* if (value) { */ +/* setVObjectUStringZValue_(curProp,fakeUnicode(value,0)); */ +/* } */ +/* } */ +/* deleteStr(value); */ +/* } */ + +static void appendValue(const char *value) +{ + char *p1, *p2; + wchar_t *p3; + int i; + + if (fieldedProp && *fieldedProp) { + if (value) { + addPropValue(curProp, *fieldedProp, value); + } + /* else this field is empty, advance to next field */ + fieldedProp++; + } else { + if (value) { + if (vObjectUStringZValue(curProp)) { + p1 = fakeCString(vObjectUStringZValue(curProp)); + p2 = malloc(sizeof(char *) * (strlen(p1)+strlen(value)+1)); + strcpy(p2, p1); + deleteStr(p1); + + i = strlen(p2); + p2[i] = ','; + p2[i+1] = '\0'; + p2 = strcat(p2, value); + p3 = (wchar_t *) vObjectUStringZValue(curProp); + free(p3); + setVObjectUStringZValue_(curProp,fakeUnicode(p2,0)); + deleteStr(p2); + } else { + setVObjectUStringZValue_(curProp,fakeUnicode(value,0)); + } + } + } + deleteStr(value); +} + + +static void enterProps(const char *s) + { + curProp = addGroup(curObj,s); + deleteStr(s); + } + +static void enterAttr(const char *s1, const char *s2) + { + const char *p1=0L, *p2=0L; + p1 = lookupProp_(s1); + if (s2) { + VObject *a; + p2 = lookupProp_(s2); + a = addProp(curProp,p1); + setVObjectStringZValue(a,p2); + } + else + addProp(curProp,p1); + if (strcasecmp(p1,VCBase64Prop) == 0 || (s2 && strcasecmp(p2,VCBase64Prop)==0)) + lexPushMode(L_BASE64); + else if (strcasecmp(p1,VCQuotedPrintableProp) == 0 + || (s2 && strcasecmp(p2,VCQuotedPrintableProp)==0)) + lexPushMode(L_QUOTED_PRINTABLE); + deleteStr(s1); deleteStr(s2); + } + + +#define MAX_LEX_LOOKAHEAD_0 32 +#define MAX_LEX_LOOKAHEAD 64 +#define MAX_LEX_MODE_STACK_SIZE 10 +#define LEXMODE() (lexBuf.lexModeStack[lexBuf.lexModeStackTop]) + +struct LexBuf { + /* input */ + FILE *inputFile; + char *inputString; + unsigned long curPos; + unsigned long inputLen; + /* lookahead buffer */ + /* -- lookahead buffer is short instead of char so that EOF + / can be represented correctly. + */ + unsigned long len; + short buf[MAX_LEX_LOOKAHEAD]; + unsigned long getPtr; + /* context stack */ + unsigned long lexModeStackTop; + enum LexMode lexModeStack[MAX_LEX_MODE_STACK_SIZE]; + /* token buffer */ + unsigned long maxToken; + char *strs; + unsigned long strsLen; + } lexBuf; + +static void lexPushMode(enum LexMode mode) + { + if (lexBuf.lexModeStackTop == (MAX_LEX_MODE_STACK_SIZE-1)) + yyerror("lexical context stack overflow"); + else { + lexBuf.lexModeStack[++lexBuf.lexModeStackTop] = mode; + } + } + +static void lexPopMode(int top) + { + /* special case of pop for ease of error recovery -- this + version will never underflow */ + if (top) + lexBuf.lexModeStackTop = 0; + else + if (lexBuf.lexModeStackTop > 0) lexBuf.lexModeStackTop--; + } + +static int lexWithinMode(enum LexMode mode) { + unsigned long i; + for (i=0;i<lexBuf.lexModeStackTop;i++) + if (mode == lexBuf.lexModeStack[i]) return 1; + return 0; + } + +static int lexGetc_() + { + /* get next char from input, no buffering. */ + if (lexBuf.curPos == lexBuf.inputLen) + return EOF; + else if (lexBuf.inputString) + return *(lexBuf.inputString + lexBuf.curPos++); + else { + if (!feof(lexBuf.inputFile)) + return fgetc(lexBuf.inputFile); + else + return EOF; + } + } + +static int lexGeta() + { + ++lexBuf.len; + return (lexBuf.buf[lexBuf.getPtr] = lexGetc_()); + } + +static int lexGeta_(int i) + { + ++lexBuf.len; + return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_()); + } + +static void lexSkipLookahead() { + if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) { + /* don't skip EOF. */ + lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD; + lexBuf.len--; + } + } + +static int lexLookahead() { + int c = (lexBuf.len)? + lexBuf.buf[lexBuf.getPtr]: + lexGeta(); + /* do the \r\n -> \n or \r -> \n translation here */ + if (c == '\r') { + int a = (lexBuf.len>1)? + lexBuf.buf[(lexBuf.getPtr+1)%MAX_LEX_LOOKAHEAD]: + lexGeta_(1); + if (a == '\n') { + lexSkipLookahead(); + } + lexBuf.buf[lexBuf.getPtr] = c = '\n'; + } + else if (c == '\n') { + int a; + if (lexBuf.len > 1) + a = lexBuf.buf[lexBuf.getPtr]; + else + a = lexGeta_(1); + if (a == '\r') { + lexSkipLookahead(); + } + lexBuf.buf[lexBuf.getPtr] = '\n'; + } + return c; + } + +static int lexGetc() { + int c = lexLookahead(); + if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) { + /* EOF will remain in lookahead buffer */ + lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD; + lexBuf.len--; + } + return c; + } + +static void lexSkipLookaheadWord() { + if (lexBuf.strsLen <= lexBuf.len) { + lexBuf.len -= lexBuf.strsLen; + lexBuf.getPtr = (lexBuf.getPtr + lexBuf.strsLen) % MAX_LEX_LOOKAHEAD; + } + } + +static void lexClearToken() + { + lexBuf.strsLen = 0; + } + +static void lexAppendc(int c) + { + /* not sure if I am doing this right to fix purify report -- PGB */ + lexBuf.strs = (char *) realloc(lexBuf.strs, (size_t) lexBuf.strsLen + 1); + lexBuf.strs[lexBuf.strsLen] = c; + /* append up to zero termination */ + if (c == 0) return; + lexBuf.strsLen++; + if (lexBuf.strsLen > lexBuf.maxToken) { + /* double the token string size */ + lexBuf.maxToken <<= 1; + lexBuf.strs = (char*) realloc(lexBuf.strs,(size_t)lexBuf.maxToken); + } + } + +static char* lexStr() { + return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1); + } + +static void lexSkipWhite() { + int c = lexLookahead(); + while (c == ' ' || c == '\t') { + lexSkipLookahead(); + c = lexLookahead(); + } + } + +static char* lexGetWord() { + int c; + lexSkipWhite(); + lexClearToken(); + c = lexLookahead(); + /* some "words" have a space in them, like "NEEDS ACTION". + this may be an oversight of the spec, but it is true nevertheless. + while (c != EOF && !strchr("\t\n ;:=",c)) { */ + while (c != EOF && !strchr("\n;:=",c)) { + lexAppendc(c); + lexSkipLookahead(); + c = lexLookahead(); + } + lexAppendc(0); + return lexStr(); + } + +void lexPushLookahead(char *s, int len) { + int putptr; + if (len == 0) len = strlen(s); + putptr = (int)lexBuf.getPtr - len; + /* this function assumes that length of word to push back + / is not greater than MAX_LEX_LOOKAHEAD. + */ + if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD; + lexBuf.getPtr = putptr; + while (*s) { + lexBuf.buf[putptr] = *s++; + putptr = (putptr + 1) % MAX_LEX_LOOKAHEAD; + } + lexBuf.len += len; + } + +static void lexPushLookaheadc(int c) { + int putptr; + /* can't putback EOF, because it never leaves lookahead buffer */ + if (c == EOF) return; + putptr = (int)lexBuf.getPtr - 1; + if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD; + lexBuf.getPtr = putptr; + lexBuf.buf[putptr] = c; + lexBuf.len += 1; + } + +static char* lexLookaheadWord() { + /* this function can lookahead word with max size of MAX_LEX_LOOKAHEAD_0 + / and thing bigger than that will stop the lookahead and return 0; + / leading white spaces are not recoverable. + */ + int c; + int len = 0; + int curgetptr = 0; + lexSkipWhite(); + lexClearToken(); + curgetptr = (int)lexBuf.getPtr; /* remember! */ + while (len < (MAX_LEX_LOOKAHEAD_0)) { + c = lexGetc(); + len++; + if (c == EOF || strchr("\t\n ;:=", c)) { + lexAppendc(0); + /* restore lookahead buf. */ + lexBuf.len += len; + lexBuf.getPtr = curgetptr; + return lexStr(); + } + else + lexAppendc(c); + } + lexBuf.len += len; /* char that has been moved to lookahead buffer */ + lexBuf.getPtr = curgetptr; + return 0; + } + +#ifdef _SUPPORT_LINE_FOLDING +static void handleMoreRFC822LineBreak(int c) { + /* suport RFC 822 line break in cases like + * ADR: foo; + * morefoo; + * more foo; + */ + if (c == ';') { + int a; + lexSkipLookahead(); + /* skip white spaces */ + a = lexLookahead(); + while (a == ' ' || a == '\t') { + lexSkipLookahead(); + a = lexLookahead(); + } + if (a == '\n') { + lexSkipLookahead(); + a = lexLookahead(); + if (a == ' ' || a == '\t') { + /* continuation, throw away all the \n and spaces read so + * far + */ + lexSkipWhite(); + lexPushLookaheadc(';'); + } + else { + lexPushLookaheadc('\n'); + lexPushLookaheadc(';'); + } + } + else { + lexPushLookaheadc(';'); + } + } + } + +static char* lexGet1Value() { + int c; + lexSkipWhite(); + c = lexLookahead(); + lexClearToken(); + while (c != EOF && c != ';') { + if (c == '\n') { + int a; + lexSkipLookahead(); + a = lexLookahead(); + if (a == ' ' || a == '\t') { + lexAppendc(' '); + lexSkipLookahead(); + } + else { + lexPushLookaheadc('\n'); + break; + } + } + else { + lexAppendc(c); + lexSkipLookahead(); + } + c = lexLookahead(); + } + lexAppendc(0); + handleMoreRFC822LineBreak(c); + return c==EOF?0:lexStr(); + } +#endif + +char* lexGetStrUntil(char *termset) { + int c = lexLookahead(); + lexClearToken(); + while (c != EOF && !strchr(termset,c)) { + lexAppendc(c); + lexSkipLookahead(); + c = lexLookahead(); + } + lexAppendc(0); + return c==EOF?0:lexStr(); + } + +static int match_begin_name(int end) { + char *n = lexLookaheadWord(); + int token = ID; + if (n) { + if (!strcasecmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD; + else if (!strcasecmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL; + else if (!strcasecmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT; + else if (!strcasecmp(n,"vtodo")) token = end?END_VTODO:BEGIN_VTODO; + deleteStr(n); + return token; + } + return 0; + } + + +void initLex(const char *inputstring, unsigned long inputlen, FILE *inputfile) + { + /* initialize lex mode stack */ + lexBuf.lexModeStack[lexBuf.lexModeStackTop=0] = L_NORMAL; + + /* iniatialize lex buffer. */ + lexBuf.inputString = (char*) inputstring; + lexBuf.inputLen = inputlen; + lexBuf.curPos = 0; + lexBuf.inputFile = inputfile; + + lexBuf.len = 0; + lexBuf.getPtr = 0; + + lexBuf.maxToken = MAXTOKEN; + lexBuf.strs = (char*)malloc(MAXTOKEN); + lexBuf.strsLen = 0; + + } + +static void finiLex() { + free(lexBuf.strs); + } + + +/****************************************************************************/ +/* This parses and converts the base64 format for binary encoding into + * a decoded buffer (allocated with new). See RFC 1521. + */ +static char * lexGetDataFromBase64() + { + unsigned long bytesLen = 0, bytesMax = 0; + int quadIx = 0, pad = 0; + unsigned long trip = 0; + unsigned char b; + int c; + unsigned char *bytes = NULL; + unsigned char *oldBytes = NULL; + + DBG_(("db: lexGetDataFromBase64\n")); + while (1) { + c = lexGetc(); + if (c == '\n') { + ++mime_lineNum; + if (lexLookahead() == '\n') { + /* a '\n' character by itself means end of data */ + break; + } + else continue; /* ignore '\n' */ + } + else { + if ((c >= 'A') && (c <= 'Z')) + b = (unsigned char)(c - 'A'); + else if ((c >= 'a') && (c <= 'z')) + b = (unsigned char)(c - 'a') + 26; + else if ((c >= '0') && (c <= '9')) + b = (unsigned char)(c - '0') + 52; + else if (c == '+') + b = 62; + else if (c == '/') + b = 63; + else if (c == '=') { + b = 0; + pad++; + } else if ((c == ' ') || (c == '\t')) { + continue; + } else { /* error condition */ + if (bytes) free(bytes); + else if (oldBytes) free(oldBytes); + /* error recovery: skip until 2 adjacent newlines. */ + DBG_(("db: invalid character 0x%x '%c'\n", c,c)); + if (c != EOF) { + c = lexGetc(); + while (c != EOF) { + if (c == '\n' && lexLookahead() == '\n') { + ++mime_lineNum; + break; + } + c = lexGetc(); + } + } + return NULL; + } + trip = (trip << 6) | b; + if (++quadIx == 4) { + unsigned char outBytes[3]; + int numOut; + int i; + for (i = 0; i < 3; i++) { + outBytes[2-i] = (unsigned char)(trip & 0xFF); + trip >>= 8; + } + numOut = 3 - pad; + if (bytesLen + numOut > bytesMax) { + if (!bytes) { + bytesMax = 1024; + bytes = (unsigned char*)malloc((size_t)bytesMax); + } + else { + bytesMax <<= 2; + oldBytes = bytes; + bytes = (unsigned char*)realloc(bytes,(size_t)bytesMax); + } + if (bytes == 0) { + mime_error("out of memory while processing BASE64 data\n"); + } + } + if (bytes) { + memcpy(bytes + bytesLen, outBytes, numOut); + bytesLen += numOut; + } + trip = 0; + quadIx = 0; + } + } + } /* while */ + DBG_(("db: bytesLen = %d\n", bytesLen)); + /* kludge: all this won't be necessary if we have tree form + representation */ + if (bytes) { + setValueWithSize(curProp,bytes,(unsigned int)bytesLen); + free(bytes); + } + else if (oldBytes) { + setValueWithSize(curProp,oldBytes,(unsigned int)bytesLen); + free(oldBytes); + } + return 0; + } + +static int match_begin_end_name(int end) { + int token; + lexSkipWhite(); + if (lexLookahead() != ':') return ID; + lexSkipLookahead(); + lexSkipWhite(); + token = match_begin_name(end); + if (token == ID) { + lexPushLookaheadc(':'); + DBG_(("db: ID '%s'\n", yylval.str)); + return ID; + } + else if (token != 0) { + lexSkipLookaheadWord(); + deleteStr(yylval.str); + DBG_(("db: begin/end %d\n", token)); + return token; + } + return 0; + } + +static char* lexGetQuotedPrintable() + { + char cur; + + lexClearToken(); + do { + cur = lexGetc(); + switch (cur) { + case '=': { + int c = 0; + int next[2]; + int i; + for (i = 0; i < 2; i++) { + next[i] = lexGetc(); + if (next[i] >= '0' && next[i] <= '9') + c = c * 16 + next[i] - '0'; + else if (next[i] >= 'A' && next[i] <= 'F') + c = c * 16 + next[i] - 'A' + 10; + else + break; + } + if (i == 0) { + /* single '=' follow by LINESEP is continuation sign? */ + if (next[0] == '\n') { + ++mime_lineNum; + } + else { + lexPushLookaheadc('='); + goto EndString; + } + } + else if (i == 1) { + lexPushLookaheadc(next[1]); + lexPushLookaheadc(next[0]); + lexAppendc('='); + } else { + lexAppendc(c); + } + break; + } /* '=' */ + case '\n': { + lexPushLookaheadc('\n'); + goto EndString; + } + case (char)EOF: + break; + default: + lexAppendc(cur); + break; + } /* switch */ + } while (cur != (char)EOF); + +EndString: + lexAppendc(0); + return lexStr(); + } /* LexQuotedPrintable */ + +static int yylex() { + + int lexmode = LEXMODE(); + if (lexmode == L_VALUES) { + int c = lexGetc(); + if (c == ';') { + DBG_(("db: SEMICOLON\n")); + lexPushLookaheadc(c); + handleMoreRFC822LineBreak(c); + lexSkipLookahead(); + return SEMICOLON; + } + else if (strchr("\n",c)) { + ++mime_lineNum; + /* consume all line separator(s) adjacent to each other */ + c = lexLookahead(); + while (strchr("\n",c)) { + lexSkipLookahead(); + c = lexLookahead(); + ++mime_lineNum; + } + DBG_(("db: LINESEP\n")); + return LINESEP; + } + else { + char *p = 0; + lexPushLookaheadc(c); + if (lexWithinMode(L_BASE64)) { + /* get each char and convert to bin on the fly... */ + p = lexGetDataFromBase64(); + yylval.str = p; + return STRING; + } + else if (lexWithinMode(L_QUOTED_PRINTABLE)) { + p = lexGetQuotedPrintable(); + } + else { +#ifdef _SUPPORT_LINE_FOLDING + p = lexGet1Value(); +#else + p = lexGetStrUntil(";\n"); +#endif + } + if (p) { + DBG_(("db: STRING: '%s'\n", p)); + yylval.str = p; + return STRING; + } + else return 0; + } + } + else { + /* normal mode */ + while (1) { + int c = lexGetc(); + switch(c) { + case ':': { + /* consume all line separator(s) adjacent to each other */ + /* ignoring linesep immediately after colon. */ + c = lexLookahead(); + while (strchr("\n",c)) { + lexSkipLookahead(); + c = lexLookahead(); + ++mime_lineNum; + } + DBG_(("db: COLON\n")); + return COLON; + } + case ';': + DBG_(("db: SEMICOLON\n")); + return SEMICOLON; + case '=': + DBG_(("db: EQ\n")); + return EQ; + /* ignore tabs/newlines in this mode. We can't ignore + * spaces, because values like NEEDS ACTION have a space. */ + case '\t': continue; + case '\n': { + ++mime_lineNum; + continue; + } + case EOF: return 0; + break; + default: { + lexPushLookaheadc(c); + if (isalpha(c) || c == ' ') { + char *t = lexGetWord(); + yylval.str = t; + if (!strcasecmp(t, "begin")) { + return match_begin_end_name(0); + } + else if (!strcasecmp(t,"end")) { + return match_begin_end_name(1); + } + else { + DBG_(("db: ID '%s'\n", t)); + return ID; + } + } + else { + /* unknown token */ + return 0; + } + break; + } + } + } + } + return 0; + } + + +/***************************************************************************/ +/*** Public Functions ****/ +/***************************************************************************/ + +static VObject* Parse_MIMEHelper() + { + ObjStackTop = -1; + mime_numErrors = 0; + mime_lineNum = 1; + vObjList = 0; + curObj = 0; + + if (yyparse() != 0) + return 0; + + finiLex(); + return vObjList; + } + +/****************************************************************************/ +VObject* Parse_MIME(const char *input, unsigned long len) + { + initLex(input, len, 0); + return Parse_MIMEHelper(); + } + + +VObject* Parse_MIME_FromFile(FILE *file) + { + VObject *result; + long startPos; + + initLex(0,(unsigned long)-1,file); + startPos = ftell(file); + if (!(result = Parse_MIMEHelper())) { + fseek(file,startPos,SEEK_SET); + } + return result; + } + +VObject* Parse_MIME_FromFileName(const char *fname) + { + FILE *fp = fopen(fname,"r"); + if (fp) { + VObject* o = Parse_MIME_FromFile(fp); + fclose(fp); + return o; + } + else { + char msg[255]; + sprintf(msg, "can't open file '%s' for reading\n", fname); + mime_error_(msg); + return 0; + } + } + +/****************************************************************************/ +void YYDebug(const char *s) +{ + Parse_Debug(s); +} + + +static MimeErrorHandler mimeErrorHandler; + +void registerMimeErrorHandler(MimeErrorHandler me) + { + mimeErrorHandler = me; + } + +static void mime_error(char *s) + { + char msg[256]; + if (mimeErrorHandler) { + sprintf(msg,"%s at line %d", s, mime_lineNum); + mimeErrorHandler(msg); + } + } + +static void mime_error_(char *s) + { + if (mimeErrorHandler) { + mimeErrorHandler(s); + } + } + diff --git a/libkcal/versit/vobject.c b/libkcal/versit/vobject.c new file mode 100644 index 000000000..e6a194728 --- /dev/null +++ b/libkcal/versit/vobject.c @@ -0,0 +1,1429 @@ +/*************************************************************************** +(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International +Business Machines Corporation and Siemens Rolm Communications Inc. + +For purposes of this license notice, the term Licensors shall mean, +collectively, Apple Computer, Inc., AT&T Corp., International +Business Machines Corporation and Siemens Rolm Communications Inc. +The term Licensor shall mean any of the Licensors. + +Subject to acceptance of the following conditions, permission is hereby +granted by Licensors without the need for written agreement and without +license or royalty fees, to use, copy, modify and distribute this +software for any purpose. + +The above copyright notice and the following four paragraphs must be +reproduced in all copies of this software and any software including +this software. + +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE +ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR +MODIFICATIONS. + +IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, +INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT +OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. + +The software is provided with RESTRICTED RIGHTS. Use, duplication, or +disclosure by the government are subject to restrictions set forth in +DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. + +***************************************************************************/ + +/* + * src: vobject.c + * doc: vobject and APIs to construct vobject, APIs pretty print + * vobject, and convert a vobject into its textual representation. + */ + +#include <stdlib.h> + +#include "vobject.h" +#include <string.h> +#include <stdio.h> + + +#define NAME_OF(o) o->id +#define VALUE_TYPE(o) o->valType +#define STRINGZ_VALUE_OF(o) o->val.strs +#define USTRINGZ_VALUE_OF(o) o->val.ustrs +#define INTEGER_VALUE_OF(o) o->val.i +#define LONG_VALUE_OF(o) o->val.l +#define ANY_VALUE_OF(o) o->val.any +#define VOBJECT_VALUE_OF(o) o->val.vobj + +const char** fieldedProp; + + + +/*---------------------------------------------------------------------- + The following functions involve with memory allocation: + newVObject + deleteVObject + dupStr + deleteStr + newStrItem + deleteStrItem + ----------------------------------------------------------------------*/ + +VObject* newVObject_(const char *id) +{ + VObject *p = (VObject*)malloc(sizeof(VObject)); + p->next = 0; + p->id = id; + p->prop = 0; + VALUE_TYPE(p) = 0; + ANY_VALUE_OF(p) = 0; + return p; +} + +VObject* newVObject(const char *id) +{ + return newVObject_(lookupStr(id)); +} + +void deleteVObject(VObject *p) +{ + if (p->id) + unUseStr(p->id); + if (p) + free(p); + p = NULL; +} + +char* dupStr(const char *s, unsigned int size) +{ + char *t; + if (size == 0) { + size = strlen(s); + } + t = (char*)malloc(size+1); + if (t) { + memcpy(t,s,size); + t[size] = 0; + return t; + } + else { + return (char*)0; + } +} + +void deleteStr(const char *p) +{ + if (p) + free((void*)p); + p = NULL; +} + + +static StrItem* newStrItem(const char *s, StrItem *next) +{ + StrItem *p = (StrItem*)malloc(sizeof(StrItem)); + p->next = next; + p->s = s; + p->refCnt = 1; + return p; +} + +static void deleteStrItem(StrItem *p) +{ + if (p) + free((void*)p); + p = NULL; +} + + +/*---------------------------------------------------------------------- + The following function provide accesses to VObject's value. + ----------------------------------------------------------------------*/ + +const char* vObjectName(VObject *o) +{ + return NAME_OF(o); +} + +void setVObjectName(VObject *o, const char* id) +{ + NAME_OF(o) = id; +} + +const char* vObjectStringZValue(VObject *o) +{ + return STRINGZ_VALUE_OF(o); +} + +void setVObjectStringZValue(VObject *o, const char *s) +{ + STRINGZ_VALUE_OF(o) = dupStr(s,0); + VALUE_TYPE(o) = VCVT_STRINGZ; +} + +void setVObjectStringZValue_(VObject *o, const char *s) +{ + STRINGZ_VALUE_OF(o) = s; + VALUE_TYPE(o) = VCVT_STRINGZ; +} + +const wchar_t* vObjectUStringZValue(VObject *o) +{ + return USTRINGZ_VALUE_OF(o); +} + +void setVObjectUStringZValue(VObject *o, const wchar_t *s) +{ + USTRINGZ_VALUE_OF(o) = (wchar_t*) dupStr((char*)s,(uStrLen(s)+1)*2); + VALUE_TYPE(o) = VCVT_USTRINGZ; +} + +void setVObjectUStringZValue_(VObject *o, const wchar_t *s) +{ + USTRINGZ_VALUE_OF(o) = s; + VALUE_TYPE(o) = VCVT_USTRINGZ; +} + +unsigned int vObjectIntegerValue(VObject *o) +{ + return INTEGER_VALUE_OF(o); +} + +void setVObjectIntegerValue(VObject *o, unsigned int i) +{ + INTEGER_VALUE_OF(o) = i; + VALUE_TYPE(o) = VCVT_UINT; +} + +unsigned long vObjectLongValue(VObject *o) +{ + return LONG_VALUE_OF(o); +} + +void setVObjectLongValue(VObject *o, unsigned long l) +{ + LONG_VALUE_OF(o) = l; + VALUE_TYPE(o) = VCVT_ULONG; +} + +void* vObjectAnyValue(VObject *o) +{ + return ANY_VALUE_OF(o); +} + +void setVObjectAnyValue(VObject *o, void *t) +{ + ANY_VALUE_OF(o) = t; + VALUE_TYPE(o) = VCVT_RAW; +} + +VObject* vObjectVObjectValue(VObject *o) +{ + return VOBJECT_VALUE_OF(o); +} + +void setVObjectVObjectValue(VObject *o, VObject *p) +{ + VOBJECT_VALUE_OF(o) = p; + VALUE_TYPE(o) = VCVT_VOBJECT; +} + +int vObjectValueType(VObject *o) +{ + return VALUE_TYPE(o); +} + + +/*---------------------------------------------------------------------- + The following functions can be used to build VObject. + ----------------------------------------------------------------------*/ + +VObject* addVObjectProp(VObject *o, VObject *p) +{ + /* circular link list pointed to tail */ + /* + o {next,id,prop,val} + V + pn {next,id,prop,val} + V + ... + p1 {next,id,prop,val} + V + pn + --> + o {next,id,prop,val} + V + pn {next,id,prop,val} + V + p {next,id,prop,val} + ... + p1 {next,id,prop,val} + V + pn + */ + + VObject *tail = o->prop; + if (tail) { + p->next = tail->next; + o->prop = tail->next = p; + } + else { + o->prop = p->next = p; + } + return p; +} + +VObject* addProp(VObject *o, const char *id) +{ + return addVObjectProp(o,newVObject(id)); +} + +VObject* addProp_(VObject *o, const char *id) +{ + return addVObjectProp(o,newVObject_(id)); +} + +void addList(VObject **o, VObject *p) +{ + p->next = 0; + if (*o == 0) { + *o = p; + } + else { + VObject *t = *o; + while (t->next) { + t = t->next; + } + t->next = p; + } +} + +VObject* nextVObjectInList(VObject *o) +{ + return o->next; +} + +VObject* setValueWithSize_(VObject *prop, void *val, unsigned int size) +{ + VObject *sizeProp; + setVObjectAnyValue(prop, val); + sizeProp = addProp(prop,VCDataSizeProp); + setVObjectLongValue(sizeProp, size); + return prop; +} + +VObject* setValueWithSize(VObject *prop, void *val, unsigned int size) +{ + void *p = dupStr(val,size); + return setValueWithSize_(prop,p,p?size:0); +} + +void initPropIterator(VObjectIterator *i, VObject *o) +{ + i->start = o->prop; + i->next = 0; +} + +void initVObjectIterator(VObjectIterator *i, VObject *o) +{ + i->start = o->next; + i->next = 0; +} + +int moreIteration(VObjectIterator *i) +{ + return (i->start && (i->next==0 || i->next!=i->start)); +} + +VObject* nextVObject(VObjectIterator *i) +{ + if (i->start && i->next != i->start) { + if (i->next == 0) { + i->next = i->start->next; + return i->next; + } + else { + i->next = i->next->next; + return i->next; + } + } + else return (VObject*)0; +} + +VObject* isAPropertyOf(VObject *o, const char *id) +{ + VObjectIterator i; + initPropIterator(&i,o); + while (moreIteration(&i)) { + VObject *each = nextVObject(&i); + if (!strcasecmp(id,each->id)) + return each; + } + return (VObject*)0; +} + +VObject* addGroup(VObject *o, const char *g) +{ + /* + a.b.c + --> + prop(c) + prop(VCGrouping=b) + prop(VCGrouping=a) + */ + char *dot = strrchr(g,'.'); + if (dot) { + VObject *p, *t; + char *gs, *n = dot+1; + gs = dupStr(g,0); /* so we can write to it. */ + /* used to be + * t = p = addProp_(o,lookupProp_(n)); + */ + t = p = addProp_(o,lookupProp(n)); + dot = strrchr(gs,'.'); + *dot = 0; + do { + dot = strrchr(gs,'.'); + if (dot) { + n = dot+1; + *dot=0; + } + else + n = gs; + /* property(VCGroupingProp=n); + * and the value may have VCGrouping property + */ + t = addProp(t,VCGroupingProp); + setVObjectStringZValue(t,lookupProp_(n)); + } while (n != gs); + deleteStr(gs); + return p; + } + else + return addProp_(o,lookupProp(g)); +} + +VObject* addPropValue(VObject *o, const char *p, const char *v) +{ + VObject *prop; + prop = addProp(o,p); + setVObjectUStringZValue_(prop, fakeUnicode(v,0)); + return prop; +} + +VObject* addPropSizedValue_(VObject *o, const char *p, const char *v, + unsigned int size) +{ + VObject *prop; + prop = addProp(o,p); + setValueWithSize_(prop, (void*)v, size); + return prop; +} + +VObject* addPropSizedValue(VObject *o, const char *p, const char *v, + unsigned int size) +{ + return addPropSizedValue_(o,p,dupStr(v,size),size); +} + + + +/*---------------------------------------------------------------------- + The following pretty print a VObject + ----------------------------------------------------------------------*/ + +static void printVObject_(FILE *fp, VObject *o, int level); + +static void indent(FILE *fp, int level) +{ + int i; + for (i=0;i<level*4;i++) { + fputc(' ', fp); + } +} + +static void printValue(FILE *fp, VObject *o, int level) +{ + switch (VALUE_TYPE(o)) { + case VCVT_USTRINGZ: { + char c; + char *t,*s; + s = t = fakeCString(USTRINGZ_VALUE_OF(o)); + fputc('"',fp); + while (c=*t,c) { + fputc(c,fp); + if (c == '\n') indent(fp,level+2); + t++; + } + fputc('"',fp); + deleteStr(s); + break; + } + case VCVT_STRINGZ: { + char c; + const char *s = STRINGZ_VALUE_OF(o); + fputc('"',fp); + while (c=*s,c) { + fputc(c,fp); + if (c == '\n') indent(fp,level+2); + s++; + } + fputc('"',fp); + break; + } + case VCVT_UINT: + fprintf(fp,"%d", INTEGER_VALUE_OF(o)); break; + case VCVT_ULONG: + fprintf(fp,"%ld", LONG_VALUE_OF(o)); break; + case VCVT_RAW: + fprintf(fp,"[raw data]"); break; + case VCVT_VOBJECT: + fprintf(fp,"[vobject]\n"); + printVObject_(fp,VOBJECT_VALUE_OF(o),level+1); + break; + case 0: + fprintf(fp,"[none]"); break; + default: + fprintf(fp,"[unknown]"); break; + } +} + +static void printNameValue(FILE *fp,VObject *o, int level) +{ + indent(fp,level); + if (NAME_OF(o)) { + fprintf(fp,"%s", NAME_OF(o)); + } + if (VALUE_TYPE(o)) { + fputc('=',fp); + printValue(fp,o, level); + } + fprintf(fp,"\n"); +} + +static void printVObject_(FILE *fp, VObject *o, int level) + { + VObjectIterator t; + if (o == 0) { + fprintf(fp,"[NULL]\n"); + return; + } + printNameValue(fp,o,level); + initPropIterator(&t,o); + while (moreIteration(&t)) { + VObject *eachProp = nextVObject(&t); + printVObject_(fp,eachProp,level+1); + } + } + +void printVObject(FILE *fp,VObject *o) +{ + printVObject_(fp,o,0); +} + +void printVObjectToFile(char *fname,VObject *o) +{ + FILE *fp = fopen(fname,"w"); + if (fp) { + printVObject(fp,o); + fclose(fp); + } +} + +void printVObjectsToFile(char *fname,VObject *list) +{ + FILE *fp = fopen(fname,"w"); + if (fp) { + while (list) { + printVObject(fp,list); + list = nextVObjectInList(list); + } + fclose(fp); + } +} + +void cleanVObject(VObject *o) +{ + if (o == 0) return; + if (o->prop) { + /* destroy time: cannot use the iterator here. + Have to break the cycle in the circular link + list and turns it into regular NULL-terminated + list -- since at some point of destruction, + the reference entry for the iterator to work + will not longer be valid. + */ + VObject *p; + p = o->prop->next; + o->prop->next = 0; + do { + VObject *t = p->next; + cleanVObject(p); + p = t; + } while (p); + } + switch (VALUE_TYPE(o)) { + case VCVT_USTRINGZ: + case VCVT_STRINGZ: + case VCVT_RAW: + /* assume they are all allocated by malloc. */ + free((char*)STRINGZ_VALUE_OF(o)); + break; + case VCVT_VOBJECT: + cleanVObject(VOBJECT_VALUE_OF(o)); + break; + } + deleteVObject(o); +} + +void cleanVObjects(VObject *list) +{ + while (list) { + VObject *t = list; + list = nextVObjectInList(list); + cleanVObject(t); + } +} + +/*---------------------------------------------------------------------- + The following is a String Table Facilities. + ----------------------------------------------------------------------*/ + +#define STRTBLSIZE 255 + +static StrItem *strTbl[STRTBLSIZE]; + +static unsigned int hashStr(const char *s) +{ + unsigned int h = 0; + int i; + for (i=0;s[i];i++) { + h += s[i]*i; + } + return h % STRTBLSIZE; +} + +const char* lookupStr(const char *s) +{ + char *newS; + + StrItem *t; + unsigned int h = hashStr(s); + if ((t = strTbl[h]) != 0) { + do { + if (strcasecmp(t->s,s) == 0) { + t->refCnt++; + return t->s; + } + t = t->next; + } while (t); + } + newS = dupStr(s,0); + strTbl[h] = newStrItem(newS,strTbl[h]); + return newS; +} + +void unUseStr(const char *s) +{ + StrItem *cur, *prev; + + unsigned int h = hashStr(s); + cur = strTbl[h]; + prev = cur; + while (cur != 0) { + if (strcasecmp(cur->s,s) == 0) { + cur->refCnt--; + /* if that was the last reference to this string, kill it. */ + if (cur->refCnt == 0) { + if (cur == strTbl[h]) { + strTbl[h] = cur->next; + deleteStr(prev->s); + deleteStrItem(prev); + } else { + prev->next = cur->next; + deleteStr(cur->s); + deleteStrItem(cur); + } + return; + } + } + prev = cur; + cur = cur->next; + } +} + +void cleanStrTbl() +{ + int i; + for (i=0; i<STRTBLSIZE;i++) { + StrItem *t = strTbl[i]; + while (t) { + StrItem *p; + deleteStr(t->s); + p = t; + t = t->next; + deleteStrItem(p); + } + strTbl[i] = 0; + } +} + + +struct PreDefProp { + const char *name; + const char *alias; + const char** fields; + unsigned int flags; + }; + +/* flags in PreDefProp */ +#define PD_BEGIN 0x1 +#define PD_INTERNAL 0x2 + +static const char *adrFields[] = { + VCPostalBoxProp, + VCExtAddressProp, + VCStreetAddressProp, + VCCityProp, + VCRegionProp, + VCPostalCodeProp, + VCCountryNameProp, + 0 +}; + +static const char *nameFields[] = { + VCFamilyNameProp, + VCGivenNameProp, + VCAdditionalNamesProp, + VCNamePrefixesProp, + VCNameSuffixesProp, + NULL + }; + +static const char *orgFields[] = { + VCOrgNameProp, + VCOrgUnitProp, + VCOrgUnit2Prop, + VCOrgUnit3Prop, + VCOrgUnit4Prop, + NULL + }; + +static const char *AAlarmFields[] = { + VCRunTimeProp, + VCSnoozeTimeProp, + VCRepeatCountProp, + VCAudioContentProp, + 0 + }; + +/* ExDate -- has unamed fields */ +/* RDate -- has unamed fields */ + +static const char *DAlarmFields[] = { + VCRunTimeProp, + VCSnoozeTimeProp, + VCRepeatCountProp, + VCDisplayStringProp, + 0 + }; + +static const char *MAlarmFields[] = { + VCRunTimeProp, + VCSnoozeTimeProp, + VCRepeatCountProp, + VCEmailAddressProp, + VCNoteProp, + 0 + }; + +static const char *PAlarmFields[] = { + VCRunTimeProp, + VCSnoozeTimeProp, + VCRepeatCountProp, + VCProcedureNameProp, + 0 + }; + +static struct PreDefProp propNames[] = { + { VC7bitProp, 0, 0, 0 }, + { VC8bitProp, 0, 0, 0 }, + { VCAAlarmProp, 0, AAlarmFields, 0 }, + { VCAdditionalNamesProp, 0, 0, 0 }, + { VCAdrProp, 0, adrFields, 0 }, + { VCAgentProp, 0, 0, 0 }, + { VCAIFFProp, 0, 0, 0 }, + { VCAOLProp, 0, 0, 0 }, + { VCAppleLinkProp, 0, 0, 0 }, + { VCAttachProp, 0, 0, 0 }, + { VCAttendeeProp, 0, 0, 0 }, + { VCATTMailProp, 0, 0, 0 }, + { VCAudioContentProp, 0, 0, 0 }, + { VCAVIProp, 0, 0, 0 }, + { VCBase64Prop, 0, 0, 0 }, + { VCBBSProp, 0, 0, 0 }, + { VCBirthDateProp, 0, 0, 0 }, + { VCBMPProp, 0, 0, 0 }, + { VCBodyProp, 0, 0, 0 }, + { VCBusinessRoleProp, 0, 0, 0 }, + { VCCalProp, 0, 0, PD_BEGIN }, + { VCCaptionProp, 0, 0, 0 }, + { VCCardProp, 0, 0, PD_BEGIN }, + { VCCarProp, 0, 0, 0 }, + { VCCategoriesProp, 0, 0, 0 }, + { VCCellularProp, 0, 0, 0 }, + { VCCGMProp, 0, 0, 0 }, + { VCCharSetProp, 0, 0, 0 }, + { VCCIDProp, VCContentIDProp, 0, 0 }, + { VCCISProp, 0, 0, 0 }, + { VCCityProp, 0, 0, 0 }, + { VCClassProp, 0, 0, 0 }, + { VCCommentProp, 0, 0, 0 }, + { VCCompletedProp, 0, 0, 0 }, + { VCContentIDProp, 0, 0, 0 }, + { VCCountryNameProp, 0, 0, 0 }, + { VCDAlarmProp, 0, DAlarmFields, 0 }, + { VCDataSizeProp, 0, 0, PD_INTERNAL }, + { VCDayLightProp, 0, 0, 0 }, + { VCDCreatedProp, 0, 0, 0 }, + { VCDeliveryLabelProp, 0, 0, 0 }, + { VCDescriptionProp, 0, 0, 0 }, + { VCDIBProp, 0, 0, 0 }, + { VCDisplayStringProp, 0, 0, 0 }, + { VCDomesticProp, 0, 0, 0 }, + { VCDTendProp, 0, 0, 0 }, + { VCDTstartProp, 0, 0, 0 }, + { VCDueProp, 0, 0, 0 }, + { VCEmailAddressProp, 0, 0, 0 }, + { VCEncodingProp, 0, 0, 0 }, + { VCEndProp, 0, 0, 0 }, + { VCEventProp, 0, 0, PD_BEGIN }, + { VCEWorldProp, 0, 0, 0 }, + { VCExNumProp, 0, 0, 0 }, + { VCExDateProp, 0, 0, 0 }, + { VCExpectProp, 0, 0, 0 }, + { VCExtAddressProp, 0, 0, 0 }, + { VCFamilyNameProp, 0, 0, 0 }, + { VCFaxProp, 0, 0, 0 }, + { VCFullNameProp, 0, 0, 0 }, + { VCGeoLocationProp, 0, 0, 0 }, + { VCGeoProp, 0, 0, 0 }, + { VCGIFProp, 0, 0, 0 }, + { VCGivenNameProp, 0, 0, 0 }, + { VCGroupingProp, 0, 0, 0 }, + { VCHomeProp, 0, 0, 0 }, + { VCIBMMailProp, 0, 0, 0 }, + { VCInlineProp, 0, 0, 0 }, + { VCInternationalProp, 0, 0, 0 }, + { VCInternetProp, 0, 0, 0 }, + { VCISDNProp, 0, 0, 0 }, + { VCJPEGProp, 0, 0, 0 }, + { VCLanguageProp, 0, 0, 0 }, + { VCLastModifiedProp, 0, 0, 0 }, + { VCLastRevisedProp, 0, 0, 0 }, + { VCLocationProp, 0, 0, 0 }, + { VCLogoProp, 0, 0, 0 }, + { VCMailerProp, 0, 0, 0 }, + { VCMAlarmProp, 0, MAlarmFields, 0 }, + { VCMCIMailProp, 0, 0, 0 }, + { VCMessageProp, 0, 0, 0 }, + { VCMETProp, 0, 0, 0 }, + { VCModemProp, 0, 0, 0 }, + { VCMPEG2Prop, 0, 0, 0 }, + { VCMPEGProp, 0, 0, 0 }, + { VCMSNProp, 0, 0, 0 }, + { VCNamePrefixesProp, 0, 0, 0 }, + { VCNameProp, 0, nameFields, 0 }, + { VCNameSuffixesProp, 0, 0, 0 }, + { VCNoteProp, 0, 0, 0 }, + { VCOrgNameProp, 0, 0, 0 }, + { VCOrgProp, 0, orgFields, 0 }, + { VCOrgUnit2Prop, 0, 0, 0 }, + { VCOrgUnit3Prop, 0, 0, 0 }, + { VCOrgUnit4Prop, 0, 0, 0 }, + { VCOrgUnitProp, 0, 0, 0 }, + { VCPagerProp, 0, 0, 0 }, + { VCPAlarmProp, 0, PAlarmFields, 0 }, + { VCParcelProp, 0, 0, 0 }, + { VCPartProp, 0, 0, 0 }, + { VCPCMProp, 0, 0, 0 }, + { VCPDFProp, 0, 0, 0 }, + { VCPGPProp, 0, 0, 0 }, + { VCPhotoProp, 0, 0, 0 }, + { VCPICTProp, 0, 0, 0 }, + { VCPMBProp, 0, 0, 0 }, + { VCPostalBoxProp, 0, 0, 0 }, + { VCPostalCodeProp, 0, 0, 0 }, + { VCPostalProp, 0, 0, 0 }, + { VCPowerShareProp, 0, 0, 0 }, + { VCPreferredProp, 0, 0, 0 }, + { VCPriorityProp, 0, 0, 0 }, + { VCProcedureNameProp, 0, 0, 0 }, + { VCProdIdProp, 0, 0, 0 }, + { VCProdigyProp, 0, 0, 0 }, + { VCPronunciationProp, 0, 0, 0 }, + { VCPSProp, 0, 0, 0 }, + { VCPublicKeyProp, 0, 0, 0 }, + { VCQPProp, VCQuotedPrintableProp, 0, 0 }, + { VCQuickTimeProp, 0, 0, 0 }, + { VCQuotedPrintableProp, 0, 0, 0 }, + { VCRDateProp, 0, 0, 0 }, + { VCRegionProp, 0, 0, 0 }, + { VCRelatedToProp, 0, 0, 0 }, + { VCRepeatCountProp, 0, 0, 0 }, + { VCResourcesProp, 0, 0, 0 }, + { VCRNumProp, 0, 0, 0 }, + { VCRoleProp, 0, 0, 0 }, + { VCRRuleProp, 0, 0, 0 }, + { VCRSVPProp, 0, 0, 0 }, + { VCRunTimeProp, 0, 0, 0 }, + { VCSequenceProp, 0, 0, 0 }, + { VCSnoozeTimeProp, 0, 0, 0 }, + { VCStartProp, 0, 0, 0 }, + { VCStatusProp, 0, 0, 0 }, + { VCStreetAddressProp, 0, 0, 0 }, + { VCSubTypeProp, 0, 0, 0 }, + { VCSummaryProp, 0, 0, 0 }, + { VCTelephoneProp, 0, 0, 0 }, + { VCTIFFProp, 0, 0, 0 }, + { VCTimeZoneProp, 0, 0, 0 }, + { VCTitleProp, 0, 0, 0 }, + { VCTLXProp, 0, 0, 0 }, + { VCTodoProp, 0, 0, PD_BEGIN }, + { VCTranspProp, 0, 0, 0 }, + { VCUniqueStringProp, 0, 0, 0 }, + { VCURLProp, 0, 0, 0 }, + { VCURLValueProp, 0, 0, 0 }, + { VCValueProp, 0, 0, 0 }, + { VCVersionProp, 0, 0, 0 }, + { VCVideoProp, 0, 0, 0 }, + { VCVoiceProp, 0, 0, 0 }, + { VCWAVEProp, 0, 0, 0 }, + { VCWMFProp, 0, 0, 0 }, + { VCWorkProp, 0, 0, 0 }, + { VCX400Prop, 0, 0, 0 }, + { VCX509Prop, 0, 0, 0 }, + { VCXRuleProp, 0, 0, 0 }, + { 0,0,0,0 } + }; + + +static struct PreDefProp* lookupPropInfo(const char* str) +{ + /* brute force for now, could use a hash table here. */ + int i; + + for (i = 0; propNames[i].name; i++) + if (strcasecmp(str, propNames[i].name) == 0) { + return &propNames[i]; + } + + return 0; +} + + +const char* lookupProp_(const char* str) +{ + int i; + + for (i = 0; propNames[i].name; i++) + if (strcasecmp(str, propNames[i].name) == 0) { + const char* s; + s = propNames[i].alias?propNames[i].alias:propNames[i].name; + return lookupStr(s); + } + return lookupStr(str); +} + + +const char* lookupProp(const char* str) +{ + int i; + + for (i = 0; propNames[i].name; i++) + if (strcasecmp(str, propNames[i].name) == 0) { + const char *s; + fieldedProp = propNames[i].fields; + s = propNames[i].alias?propNames[i].alias:propNames[i].name; + return lookupStr(s); + } + fieldedProp = 0; + return lookupStr(str); +} + + +/*---------------------------------------------------------------------- + APIs to Output text form. + ----------------------------------------------------------------------*/ +#define OFILE_REALLOC_SIZE 256 +typedef struct OFile { + FILE *fp; + char *s; + int len; + int limit; + int alloc:1; + int fail:1; + } OFile; + + +/* vCalendar files need crlf linebreaks. The disabled functions didn't provide + that. */ +#if 0 + +static void appendsOFile(OFile *fp, const char *s) +{ + int slen; + if (fp->fail) return; + slen = strlen(s); + if (fp->fp) { + fwrite(s,1,slen,fp->fp); + } + else { +stuff: + if (fp->len + slen < fp->limit) { + memcpy(fp->s+fp->len,s,slen); + fp->len += slen; + return; + } + else if (fp->alloc) { + fp->limit = fp->limit + OFILE_REALLOC_SIZE; + if (OFILE_REALLOC_SIZE <= slen) fp->limit += slen; + if (fp->s) + fp->s = realloc(fp->s,fp->limit); + else + fp->s = malloc(fp->limit); + if (fp->s) goto stuff; + } + if (fp->alloc) + free(fp->s); + fp->s = 0; + fp->fail = 1; + } +} + +static void appendcOFile(OFile *fp, char c) +{ + if (fp->fail) return; + if (fp->fp) { + fputc(c,fp->fp); + } + else { +stuff: + if (fp->len+1 < fp->limit) { + fp->s[fp->len] = c; + fp->len++; + return; + } + else if (fp->alloc) { + fp->limit = fp->limit + OFILE_REALLOC_SIZE; + fp->s = realloc(fp->s,fp->limit); + if (fp->s) goto stuff; + } + if (fp->alloc) + free(fp->s); + fp->s = 0; + fp->fail = 1; + } +} + +#else + +static void appendcOFile_(OFile *fp, char c) +{ + if (fp->fail) return; + if (fp->fp) { + fputc(c,fp->fp); + } + else { +stuff: + if (fp->len+1 < fp->limit) { + fp->s[fp->len] = c; + fp->len++; + return; + } + else if (fp->alloc) { + fp->limit = fp->limit + OFILE_REALLOC_SIZE; + fp->s = realloc(fp->s,fp->limit); + if (fp->s) goto stuff; + } + if (fp->alloc) + free(fp->s); + fp->s = 0; + fp->fail = 1; + } +} + +static void appendcOFile(OFile *fp, char c) +{ + if (c == '\n') { + /* write out as <CR><LF> */ + appendcOFile_(fp,0xd); + appendcOFile_(fp,0xa); + } + else + appendcOFile_(fp,c); +} + +static void appendsOFile(OFile *fp, const char *s) +{ + int i, slen; + slen = strlen(s); + for (i=0; i<slen; i++) { + appendcOFile(fp,s[i]); + } +} + +#endif + +static void initOFile(OFile *fp, FILE *ofp) +{ + fp->fp = ofp; + fp->s = 0; + fp->len = 0; + fp->limit = 0; + fp->alloc = 0; + fp->fail = 0; +} + +static void initMemOFile(OFile *fp, char *s, int len) +{ + fp->fp = 0; + fp->s = s; + fp->len = 0; + fp->limit = s?len:0; + fp->alloc = s?0:1; + fp->fail = 0; +} + + +static int writeBase64(OFile *fp, unsigned char *s, long len) +{ + long cur = 0; + int i, numQuads = 0; + unsigned long trip; + unsigned char b; + char quad[5]; +#define MAXQUADS 16 + + quad[4] = 0; + + while (cur < len) { + /* collect the triplet of bytes into 'trip' */ + trip = 0; + for (i = 0; i < 3; i++) { + b = (cur < len) ? *(s + cur) : 0; + cur++; + trip = trip << 8 | b; + } + /* fill in 'quad' with the appropriate four characters */ + for (i = 3; i >= 0; i--) { + b = (unsigned char)(trip & 0x3F); + trip = trip >> 6; + if ((3 - i) < (cur - len)) + quad[i] = '='; /* pad char */ + else if (b < 26) quad[i] = (char)b + 'A'; + else if (b < 52) quad[i] = (char)(b - 26) + 'a'; + else if (b < 62) quad[i] = (char)(b - 52) + '0'; + else if (b == 62) quad[i] = '+'; + else quad[i] = '/'; + } + /* now output 'quad' with appropriate whitespace and line ending */ + appendsOFile(fp, (numQuads == 0 ? " " : "")); + appendsOFile(fp, quad); + appendsOFile(fp, ((cur >= len)?"\n" :(numQuads==MAXQUADS-1?"\n" : ""))); + numQuads = (numQuads + 1) % MAXQUADS; + } + appendcOFile(fp,'\n'); + + return 1; +} + +/* this function really sucks. Too basic. */ +static void writeQPString(OFile *fp, const char *s, int qp) +{ + const char *p = s; + while (*p) { + if (*p == '\n') { + if (p[1]) appendsOFile(fp,"=0A="); + } + if (*p == '=' && qp) + appendsOFile(fp,"=3D"); + else + appendcOFile(fp,*p); + p++; + } +} + +static void writeVObject_(OFile *fp, VObject *o); + +static void writeValue(OFile *fp, VObject *o, unsigned long size) +{ + if (o == 0) return; + switch (VALUE_TYPE(o)) { + case VCVT_USTRINGZ: { + char *s = fakeCString(USTRINGZ_VALUE_OF(o)); + if (isAPropertyOf(o, VCQuotedPrintableProp)) + writeQPString(fp, s, 1); + else + writeQPString(fp, s, 0); + deleteStr(s); + break; + } + case VCVT_STRINGZ: { + if (isAPropertyOf(o, VCQuotedPrintableProp)) + writeQPString(fp, STRINGZ_VALUE_OF(o), 1); + else + writeQPString(fp, STRINGZ_VALUE_OF(o), 0); + break; + } + case VCVT_UINT: { + char buf[16]; + snprintf(buf,sizeof(buf),"%u", INTEGER_VALUE_OF(o)); + appendsOFile(fp,buf); + break; + } + case VCVT_ULONG: { + char buf[16]; + snprintf(buf,sizeof(buf),"%lu", LONG_VALUE_OF(o)); + appendsOFile(fp,buf); + break; + } + case VCVT_RAW: { + appendcOFile(fp,'\n'); + writeBase64(fp,(unsigned char*)(ANY_VALUE_OF(o)),size); + break; + } + case VCVT_VOBJECT: + appendcOFile(fp,'\n'); + writeVObject_(fp,VOBJECT_VALUE_OF(o)); + break; + } +} + +static void writeAttrValue(OFile *fp, VObject *o) +{ + if (NAME_OF(o)) { + struct PreDefProp *pi; + pi = lookupPropInfo(NAME_OF(o)); + if (pi && ((pi->flags & PD_INTERNAL) != 0)) return; + appendcOFile(fp,';'); + appendsOFile(fp,NAME_OF(o)); + } + else + appendcOFile(fp,';'); + if (VALUE_TYPE(o)) { + appendcOFile(fp,'='); + writeValue(fp,o,0); + } +} + +static void writeGroup(OFile *fp, VObject *o) +{ + char buf1[256]; + char buf2[256]; + strcpy(buf1,NAME_OF(o)); + while ((o=isAPropertyOf(o,VCGroupingProp)) != 0) { + strncpy(buf2,STRINGZ_VALUE_OF(o),sizeof(buf2)); + buf2[sizeof(buf2)-1] = '\0'; + strncat(buf2,".",sizeof(buf2)-strlen(buf2)-1); + strncat(buf2,buf1,sizeof(buf2)-strlen(buf2)-1); + strcpy(buf1,buf2); + } + appendsOFile(fp,buf1); +} + +static int inList(const char **list, const char *s) +{ + if (list == 0) return 0; + while (*list) { + if (strcasecmp(*list,s) == 0) return 1; + list++; + } + return 0; +} + +static void writeProp(OFile *fp, VObject *o) +{ + if (NAME_OF(o)) { + struct PreDefProp *pi; + VObjectIterator t; + const char **fields_ = 0; + pi = lookupPropInfo(NAME_OF(o)); + if (pi && ((pi->flags & PD_BEGIN) != 0)) { + writeVObject_(fp,o); + return; + } + if (isAPropertyOf(o,VCGroupingProp)) + writeGroup(fp,o); + else + appendsOFile(fp,NAME_OF(o)); + if (pi) fields_ = pi->fields; + initPropIterator(&t,o); + while (moreIteration(&t)) { + const char *s; + VObject *eachProp = nextVObject(&t); + s = NAME_OF(eachProp); + if (strcasecmp(VCGroupingProp,s) && !inList(fields_,s)) + writeAttrValue(fp,eachProp); + } + if (fields_) { + int i = 0, n = 0; + const char** fields = fields_; + /* output prop as fields */ + appendcOFile(fp,':'); + while (*fields) { + VObject *tl = isAPropertyOf(o,*fields); + i++; + if (tl) n = i; + fields++; + } + fields = fields_; + for (i=0;i<n;i++) { + writeValue(fp,isAPropertyOf(o,*fields),0); + fields++; + if (i<(n-1)) appendcOFile(fp,';'); + } + } + } + + if (VALUE_TYPE(o)) { + unsigned long size = 0; + VObject *p = isAPropertyOf(o,VCDataSizeProp); + if (p) size = LONG_VALUE_OF(p); + appendcOFile(fp,':'); + writeValue(fp,o,size); + } + + appendcOFile(fp,'\n'); +} + +static void writeVObject_(OFile *fp, VObject *o) +{ + if (NAME_OF(o)) { + struct PreDefProp *pi; + pi = lookupPropInfo(NAME_OF(o)); + + if (pi && ((pi->flags & PD_BEGIN) != 0)) { + VObjectIterator t; + const char *begin = NAME_OF(o); + appendsOFile(fp,"BEGIN:"); + appendsOFile(fp,begin); + appendcOFile(fp,'\n'); + initPropIterator(&t,o); + while (moreIteration(&t)) { + VObject *eachProp = nextVObject(&t); + writeProp(fp, eachProp); + } + appendsOFile(fp,"END:"); + appendsOFile(fp,begin); + appendsOFile(fp,"\n\n"); + } + } +} + +void writeVObject(FILE *fp, VObject *o) +{ + OFile ofp; + initOFile(&ofp,fp); + writeVObject_(&ofp,o); +} + +void writeVObjectToFile(char *fname, VObject *o) +{ + FILE *fp = fopen(fname,"w"); + if (fp) { + writeVObject(fp,o); + fclose(fp); + } +} + +void writeVObjectsToFile(char *fname, VObject *list) +{ + FILE *fp = fopen(fname,"w"); + if (fp) { + while (list) { + writeVObject(fp,list); + list = nextVObjectInList(list); + } + fclose(fp); + } +} + +char* writeMemVObject(char *s, int *len, VObject *o) +{ + OFile ofp; + initMemOFile(&ofp,s,len?*len:0); + writeVObject_(&ofp,o); + if (len) *len = ofp.len; + appendcOFile(&ofp,0); + return ofp.s; +} + +char* writeMemVObjects(char *s, int *len, VObject *list) +{ + OFile ofp; + initMemOFile(&ofp,s,len?*len:0); + while (list) { + writeVObject_(&ofp,list); + list = nextVObjectInList(list); + } + if (len) *len = ofp.len; + appendcOFile(&ofp,0); + return ofp.s; +} + +/*---------------------------------------------------------------------- + APIs to do fake Unicode stuff. + ----------------------------------------------------------------------*/ +wchar_t* fakeUnicode(const char *ps, int *bytes) +{ + wchar_t *r, *pw; + int len = strlen(ps)+1; + + pw = r = (wchar_t*)malloc(sizeof(wchar_t)*len); + if (bytes) + *bytes = len * sizeof(wchar_t); + + while (*ps) { + if (*ps == '\n') + *pw = (wchar_t)0x2028; + else if (*ps == '\r') + *pw = (wchar_t)0x2029; + else + *pw = (wchar_t)(unsigned char)*ps; + ps++; pw++; + } + *pw = (wchar_t)0; + + return r; +} + +int uStrLen(const wchar_t *u) +{ + int i = 0; + while (*u != (wchar_t)0) { u++; i++; } + return i; +} + +char* fakeCString(const wchar_t *u) +{ + char *s, *t; + int len = uStrLen(u) + 1; + t = s = (char*)malloc(len+1); + while (*u) { + if (*u == (wchar_t)0x2028) + *t = '\n'; + else if (*u == (wchar_t)0x2029) + *t = '\r'; + else + *t = (char)*u; + u++; t++; + } + *t = 0; + return s; +} + +/* end of source file vobject.c */ diff --git a/libkcal/versit/vobject.h b/libkcal/versit/vobject.h new file mode 100644 index 000000000..0ec8b317b --- /dev/null +++ b/libkcal/versit/vobject.h @@ -0,0 +1,384 @@ +/*************************************************************************** +(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International +Business Machines Corporation and Siemens Rolm Communications Inc. + +For purposes of this license notice, the term Licensors shall mean, +collectively, Apple Computer, Inc., AT&T Corp., International +Business Machines Corporation and Siemens Rolm Communications Inc. +The term Licensor shall mean any of the Licensors. + +Subject to acceptance of the following conditions, permission is hereby +granted by Licensors without the need for written agreement and without +license or royalty fees, to use, copy, modify and distribute this +software for any purpose. + +The above copyright notice and the following four paragraphs must be +reproduced in all copies of this software and any software including +this software. + +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE +ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR +MODIFICATIONS. + +IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, +INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT +OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. + +The software is provided with RESTRICTED RIGHTS. Use, duplication, or +disclosure by the government are subject to restrictions set forth in +DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. + +***************************************************************************/ + +/* + +The vCard/vCalendar C interface is implemented in the set +of files as follows: + +vcc.y, yacc source, and vcc.c, the yacc output you will use +implements the core parser + +vobject.c implements an API that insulates the caller from +the parser and changes in the vCard/vCalendar BNF + +port.h defines compilation environment dependent stuff + +vcc.h and vobject.h are header files for their .c counterparts + +vcaltmp.h and vcaltmp.c implement vCalendar "macro" functions +which you may find useful. + +test.c is a standalone test driver that exercises some of +the features of the APIs provided. Invoke test.exe on a +VCARD/VCALENDAR input text file and you will see the pretty +print output of the internal representation (this pretty print +output should give you a good idea of how the internal +representation looks like -- there is one such output in the +following too). Also, a file with the .out suffix is generated +to show that the internal representation can be written back +in the original text format. + +For more information on this API see the readme.txt file +which accompanied this distribution. + + Also visit: + + http://www.versit.com + http://www.ralden.com + +*/ + + +#ifndef __VOBJECT_H__ +#define __VOBJECT_H__ 1 + + +#include "port.h" +#include <stdlib.h> +#include <stdio.h> + +#if defined(__CPLUSPLUS__) || defined(__cplusplus) +extern "C" { +#endif + + +#define VC7bitProp "7BIT" +#define VC8bitProp "8BIT" +#define VCAAlarmProp "AALARM" +#define VCAdditionalNamesProp "ADDN" +#define VCAdrProp "ADR" +#define VCAgentProp "AGENT" +#define VCAIFFProp "AIFF" +#define VCAOLProp "AOL" +#define VCAppleLinkProp "APPLELINK" +#define VCAttachProp "ATTACH" +#define VCAttendeeProp "ATTENDEE" +#define VCATTMailProp "ATTMAIL" +#define VCAudioContentProp "AUDIOCONTENT" +#define VCAVIProp "AVI" +#define VCBase64Prop "BASE64" +#define VCBBSProp "BBS" +#define VCBirthDateProp "BDAY" +#define VCBMPProp "BMP" +#define VCBodyProp "BODY" +#define VCBusinessRoleProp "ROLE" +#define VCCalProp "VCALENDAR" +#define VCCaptionProp "CAP" +#define VCCardProp "VCARD" +#define VCCarProp "CAR" +#define VCCategoriesProp "CATEGORIES" +#define VCCellularProp "CELL" +#define VCCGMProp "CGM" +#define VCCharSetProp "CS" +#define VCCIDProp "CID" +#define VCCISProp "CIS" +#define VCCityProp "L" +#define VCClassProp "CLASS" +#define VCCommentProp "NOTE" +#define VCCompletedProp "COMPLETED" +#define VCContentIDProp "CONTENT-ID" +#define VCCountryNameProp "C" +#define VCDAlarmProp "DALARM" +#define VCDataSizeProp "DATASIZE" +#define VCDayLightProp "DAYLIGHT" +#define VCDCreatedProp "DCREATED" +#define VCDeliveryLabelProp "LABEL" +#define VCDescriptionProp "DESCRIPTION" +#define VCDIBProp "DIB" +#define VCDisplayStringProp "DISPLAYSTRING" +#define VCDomesticProp "DOM" +#define VCDTendProp "DTEND" +#define VCDTstartProp "DTSTART" +#define VCDueProp "DUE" +#define VCEmailAddressProp "EMAIL" +#define VCEncodingProp "ENCODING" +#define VCEndProp "END" +#define VCEventProp "VEVENT" +#define VCEWorldProp "EWORLD" +#define VCExNumProp "EXNUM" +#define VCExDateProp "EXDATE" +#define VCExpectProp "EXPECT" +#define VCExtAddressProp "EXT ADD" +#define VCFamilyNameProp "F" +#define VCFaxProp "FAX" +#define VCFullNameProp "FN" +#define VCGeoProp "GEO" +#define VCGeoLocationProp "GEO" +#define VCGIFProp "GIF" +#define VCGivenNameProp "G" +#define VCGroupingProp "Grouping" +#define VCHomeProp "HOME" +#define VCIBMMailProp "IBMMail" +#define VCInlineProp "INLINE" +#define VCInternationalProp "INTL" +#define VCInternetProp "INTERNET" +#define VCISDNProp "ISDN" +#define VCJPEGProp "JPEG" +#define VCLanguageProp "LANG" +#define VCLastModifiedProp "LAST-MODIFIED" +#define VCLastRevisedProp "REV" +#define VCLocationProp "LOCATION" +#define VCLogoProp "LOGO" +#define VCMailerProp "MAILER" +#define VCMAlarmProp "MALARM" +#define VCMCIMailProp "MCIMAIL" +#define VCMessageProp "MSG" +#define VCMETProp "MET" +#define VCModemProp "MODEM" +#define VCMPEG2Prop "MPEG2" +#define VCMPEGProp "MPEG" +#define VCMSNProp "MSN" +#define VCNamePrefixesProp "NPRE" +#define VCNameProp "N" +#define VCNameSuffixesProp "NSUF" +#define VCNoteProp "NOTE" +#define VCOrgNameProp "ORGNAME" +#define VCOrgProp "ORG" +#define VCOrgUnit2Prop "OUN2" +#define VCOrgUnit3Prop "OUN3" +#define VCOrgUnit4Prop "OUN4" +#define VCOrgUnitProp "OUN" +#define VCPagerProp "PAGER" +#define VCPAlarmProp "PALARM" +#define VCParcelProp "PARCEL" +#define VCPartProp "PART" +#define VCPCMProp "PCM" +#define VCPDFProp "PDF" +#define VCPGPProp "PGP" +#define VCPhotoProp "PHOTO" +#define VCPICTProp "PICT" +#define VCPMBProp "PMB" +#define VCPostalBoxProp "BOX" +#define VCPostalCodeProp "PC" +#define VCPostalProp "POSTAL" +#define VCPowerShareProp "POWERSHARE" +#define VCPreferredProp "PREF" +#define VCPriorityProp "PRIORITY" +#define VCProcedureNameProp "PROCEDURENAME" +#define VCProdIdProp "PRODID" +#define VCProdigyProp "PRODIGY" +#define VCPronunciationProp "SOUND" +#define VCPSProp "PS" +#define VCPublicKeyProp "KEY" +#define VCQPProp "QP" +#define VCQuickTimeProp "QTIME" +#define VCQuotedPrintableProp "QUOTED-PRINTABLE" +#define VCRDateProp "RDATE" +#define VCRegionProp "R" +#define VCRelatedToProp "RELATED-TO" +#define VCRepeatCountProp "REPEATCOUNT" +#define VCResourcesProp "RESOURCES" +#define VCRNumProp "RNUM" +#define VCRoleProp "ROLE" +#define VCRRuleProp "RRULE" +#define VCRSVPProp "RSVP" +#define VCRunTimeProp "RUNTIME" +#define VCSequenceProp "SEQUENCE" +#define VCSnoozeTimeProp "SNOOZETIME" +#define VCStartProp "START" +#define VCStatusProp "STATUS" +#define VCStreetAddressProp "STREET" +#define VCSubTypeProp "SUBTYPE" +#define VCSummaryProp "SUMMARY" +#define VCTelephoneProp "TEL" +#define VCTIFFProp "TIFF" +#define VCTimeZoneProp "TZ" +#define VCTitleProp "TITLE" +#define VCTLXProp "TLX" +#define VCTodoProp "VTODO" +#define VCTranspProp "TRANSP" +#define VCUniqueStringProp "UID" +#define VCURLProp "URL" +#define VCURLValueProp "URLVAL" +#define VCValueProp "VALUE" +#define VCVersionProp "VERSION" +#define VCVideoProp "VIDEO" +#define VCVoiceProp "VOICE" +#define VCWAVEProp "WAVE" +#define VCWMFProp "WMF" +#define VCWorkProp "WORK" +#define VCX400Prop "X400" +#define VCX509Prop "X509" +#define VCXRuleProp "XRULE" + +/* extensions for KOrganizer / KPilot */ +#define KPilotIdProp "X-PILOTID" +#define KPilotStatusProp "X-PILOTSTAT" + +/* extensions for iMIP / iTIP */ +#define ICOrganizerProp "X-ORGANIZER" +#define ICMethodProp "X-METHOD" +#define ICRequestStatusProp "X-REQUEST-STATUS" + +typedef struct VObject VObject; + +typedef union ValueItem { + const char *strs; + const wchar_t *ustrs; + unsigned int i; + unsigned long l; + void *any; + VObject *vobj; + } ValueItem; + +struct VObject { + VObject *next; + const char *id; + VObject *prop; + unsigned short valType; + ValueItem val; + }; + +typedef struct StrItem StrItem; + +struct StrItem { + StrItem *next; + const char *s; + unsigned int refCnt; + }; + +typedef struct VObjectIterator { + VObject* start; + VObject* next; + } VObjectIterator; + +extern VObject* newVObject(const char *id); +extern void deleteVObject(VObject *p); +extern char* dupStr(const char *s, unsigned int size); +extern void deleteStr(const char *p); +extern void unUseStr(const char *s); + +extern void setVObjectName(VObject *o, const char* id); +extern void setVObjectStringZValue(VObject *o, const char *s); +extern void setVObjectStringZValue_(VObject *o, const char *s); +extern void setVObjectUStringZValue(VObject *o, const wchar_t *s); +extern void setVObjectUStringZValue_(VObject *o, const wchar_t *s); +extern void setVObjectIntegerValue(VObject *o, unsigned int i); +extern void setVObjectLongValue(VObject *o, unsigned long l); +extern void setVObjectAnyValue(VObject *o, void *t); +extern VObject* setValueWithSize(VObject *prop, void *val, unsigned int size); +extern VObject* setValueWithSize_(VObject *prop, void *val, unsigned int size); + +extern const char* vObjectName(VObject *o); +extern const char* vObjectStringZValue(VObject *o); +extern const wchar_t* vObjectUStringZValue(VObject *o); +extern unsigned int vObjectIntegerValue(VObject *o); +extern unsigned long vObjectLongValue(VObject *o); +extern void* vObjectAnyValue(VObject *o); +extern VObject* vObjectVObjectValue(VObject *o); +extern void setVObjectVObjectValue(VObject *o, VObject *p); + +extern VObject* addVObjectProp(VObject *o, VObject *p); +extern VObject* addProp(VObject *o, const char *id); +extern VObject* addProp_(VObject *o, const char *id); +extern VObject* addPropValue(VObject *o, const char *p, const char *v); +extern VObject* addPropSizedValue_(VObject *o, const char *p, const char *v, unsigned int size); +extern VObject* addPropSizedValue(VObject *o, const char *p, const char *v, unsigned int size); +extern VObject* addGroup(VObject *o, const char *g); +extern void addList(VObject **o, VObject *p); + +extern VObject* isAPropertyOf(VObject *o, const char *id); + +extern VObject* nextVObjectInList(VObject *o); +extern void initPropIterator(VObjectIterator *i, VObject *o); +extern int moreIteration(VObjectIterator *i); +extern VObject* nextVObject(VObjectIterator *i); + +extern char* writeMemVObject(char *s, int *len, VObject *o); +extern char* writeMemVObjects(char *s, int *len, VObject *list); + +extern const char* lookupStr(const char *s); +extern void cleanStrTbl(); + +extern void cleanVObject(VObject *o); +extern void cleanVObjects(VObject *list); + +extern const char* lookupProp(const char* str); +extern const char* lookupProp_(const char* str); + +extern wchar_t* fakeUnicode(const char *ps, int *bytes); +extern int uStrLen(const wchar_t *u); +extern char* fakeCString(const wchar_t *u); + +extern void printVObjectToFile(char *fname,VObject *o); +extern void printVObjectsToFile(char *fname,VObject *list); +extern void writeVObjectToFile(char *fname, VObject *o); +extern void writeVObjectsToFile(char *fname, VObject *list); + +extern int vObjectValueType(VObject *o); + +/* return type of vObjectValueType: */ +#define VCVT_NOVALUE 0 + /* if the VObject has no value associated with it. */ +#define VCVT_STRINGZ 1 + /* if the VObject has value set by setVObjectStringZValue. */ +#define VCVT_USTRINGZ 2 + /* if the VObject has value set by setVObjectUStringZValue. */ +#define VCVT_UINT 3 + /* if the VObject has value set by setVObjectIntegerValue. */ +#define VCVT_ULONG 4 + /* if the VObject has value set by setVObjectLongValue. */ +#define VCVT_RAW 5 + /* if the VObject has value set by setVObjectAnyValue. */ +#define VCVT_VOBJECT 6 + /* if the VObject has value set by setVObjectVObjectValue. */ + +extern const char** fieldedProp; + +extern void printVObject(FILE *fp,VObject *o); +extern void writeVObject(FILE *fp, VObject *o); + + +#if defined(__CPLUSPLUS__) || defined(__cplusplus) +} +#endif + +#endif /* __VOBJECT_H__ */ + + |