Set version to v1.1
[mverbiste] / verbiste / c-api.cpp
1 /*  $Id: c-api.cpp,v 1.14 2011/01/25 02:29:44 sarrazip Exp $
2     FrenchVerbDictionary.cpp - Dictionary of verbs and conjugation templates
3
4     verbiste - French conjugation system
5     Copyright (C) 2003-2010 Pierre Sarrazin <http://sarrazip.com/>
6
7     This program is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License
9     as published by the Free Software Foundation; either version 2
10     of the License, or (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20     02111-1307, USA.
21 */
22
23 #include <verbiste/FrenchVerbDictionary.h>
24
25 #include <verbiste/misc-types.h>
26
27 #include <iostream>
28 #include <errno.h>
29 #include <string.h>
30
31 using namespace std;
32 using namespace verbiste;
33
34 #define malloc @FORBIDDEN@
35 #define free @FORBIDDEN@
36
37
38 typedef vector<string> VS;
39 typedef vector<VS> VVS;
40
41
42 const Verbiste_ModeTense verbiste_valid_modes_and_tenses[] =
43 {
44     { VERBISTE_INFINITIVE_MODE,   VERBISTE_PRESENT_TENSE },
45
46     { VERBISTE_INDICATIVE_MODE,   VERBISTE_PRESENT_TENSE },
47     { VERBISTE_INDICATIVE_MODE,   VERBISTE_IMPERFECT_TENSE },
48     { VERBISTE_INDICATIVE_MODE,   VERBISTE_FUTURE_TENSE },
49     { VERBISTE_INDICATIVE_MODE,   VERBISTE_PAST_TENSE },
50
51     { VERBISTE_CONDITIONAL_MODE,  VERBISTE_PRESENT_TENSE },
52
53     { VERBISTE_SUBJUNCTIVE_MODE,  VERBISTE_PRESENT_TENSE },
54     { VERBISTE_SUBJUNCTIVE_MODE,  VERBISTE_IMPERFECT_TENSE },
55
56     { VERBISTE_IMPERATIVE_MODE,   VERBISTE_PRESENT_TENSE },
57
58     { VERBISTE_PARTICIPLE_MODE,   VERBISTE_PRESENT_TENSE },
59     { VERBISTE_PARTICIPLE_MODE,   VERBISTE_PAST_TENSE },
60
61     { VERBISTE_GERUND_MODE,       VERBISTE_PRESENT_TENSE },  // Italian only
62
63     { VERBISTE_INVALID_MODE,      VERBISTE_INVALID_TENSE }  // marks the end
64 };
65
66
67
68 static FrenchVerbDictionary *fvd = NULL;
69 static string constructionLogicError;
70
71
72 /*  Returns a dynamically allocated copy of the given C string.
73     Example: char *p0 = strnew("foo"); delete [] p0;
74     Example: char *p1 = strnew(""); delete [] p1;
75     Example: char *p2 = strnew(NULL); delete [] p2;
76     @param        c_str         '\0'-terminated string; allowed to be NULL
77     @returns                    a pointer to an array of characters that was
78                                 allocated by new[] and which must be destroyed
79                                 by the caller with delete[]; if 'c_str' was
80                                 NULL, the returned pointer is NULL.
81 */
82 inline
83 char *
84 strnew(const char *c_str)
85 {
86     if (c_str == NULL)
87         return NULL;
88     return strcpy(new char[strlen(c_str) + 1], c_str);
89 }
90
91
92 /*  Returns a dynamically allocated copy of the given string.
93     @param        s                string that contains no '\0' characters
94     @returns                        a pointer as with strnew(const char *)
95 */
96 inline
97 char *
98 strnew(const string &s)
99 {
100     return strnew(s.c_str());
101 }
102
103
104 int
105 verbiste_init(const char *conjugation_filename, const char *verbs_filename, const char *lang_code)
106 {
107     if (fvd != NULL)
108         return -1;
109     if (lang_code == NULL)
110         lang_code = "";
111
112     try
113     {
114         FrenchVerbDictionary::Language lang = FrenchVerbDictionary::parseLanguageCode(lang_code);
115         fvd = new FrenchVerbDictionary(conjugation_filename, verbs_filename, false, lang);
116     }
117     catch (logic_error &e)
118     {
119         constructionLogicError = e.what();
120         return -2;
121     }
122
123     return 0;
124 }
125
126
127 const char *
128 verbiste_get_init_error()
129 {
130     return constructionLogicError.c_str();
131 }
132
133
134 int
135 verbiste_close(void)
136 {
137     if (fvd == NULL)
138         return -1;
139
140     delete fvd;
141     fvd = NULL;
142     return 0;
143 }
144
145
146 void
147 verbiste_free_string(char *str)
148 {
149     delete [] str;
150 }
151
152
153 const char *
154 verbiste_get_mode_name(Verbiste_Mode mode)
155 {
156     return FrenchVerbDictionary::getModeName((Mode) mode);
157 }
158
159
160 const char *
161 verbiste_get_tense_name(Verbiste_Tense tense)
162 {
163     return FrenchVerbDictionary::getTenseName((Tense) tense);
164 }
165
166
167 static
168 Verbiste_ModeTensePersonNumber *
169 createModeTensePersonNumberArray(const vector<InflectionDesc> &vec)
170 {
171     size_t vecSize = vec.size();
172
173     Verbiste_ModeTensePersonNumber *array =
174                         new Verbiste_ModeTensePersonNumber[vecSize + 1];
175     if (array == NULL)
176         return NULL;
177
178     for (size_t i = 0; i < vecSize; i++)
179     {
180         array[i].infinitive_verb = strnew(vec[i].infinitive.c_str());
181         vec[i].mtpn.dump(array[i]);
182     }
183
184     array[vecSize].infinitive_verb = NULL;
185     array[vecSize].mode = VERBISTE_INVALID_MODE;
186     array[vecSize].tense = VERBISTE_INVALID_TENSE;
187     array[vecSize].person = 0;
188     array[vecSize].plural = false;
189
190     return array;
191 }
192
193
194 Verbiste_ModeTensePersonNumber *
195 verbiste_deconjugate(const char *verb)
196 {
197     vector<InflectionDesc> vec;
198     fvd->deconjugate(verb, vec);
199     return createModeTensePersonNumberArray(vec);
200 }
201
202
203 void
204 verbiste_free_mtpn_array(Verbiste_ModeTensePersonNumber *array)
205 {
206     if (array == NULL)
207         return;
208
209     for (size_t i = 0; array[i].infinitive_verb != NULL; i++)
210         delete [] array[i].infinitive_verb;
211
212     delete [] array;
213 }
214
215
216 static
217 int
218 generateTense(VVS &conjug,
219                 const char *infinitive,
220                 const char *templateName,
221                 Verbiste_Mode mode,
222                 Verbiste_Tense tense,
223                 bool include_pronouns)
224 {
225     const TemplateSpec *templ = fvd->getTemplate(templateName);
226     if (templ == NULL)
227         return -2;
228     string radical = FrenchVerbDictionary::getRadical(infinitive, templateName);
229
230     fvd->generateTense(radical, *templ, (Mode) mode, (Tense) tense, conjug,
231                         include_pronouns,
232                         fvd->isVerbStartingWithAspirateH(infinitive),
233                         false);
234     return 0;
235 }
236
237
238 Verbiste_TemplateArray
239 verbiste_get_verb_template_array(const char *infinitive_verb)
240 {
241     if (infinitive_verb == NULL)
242         return NULL;
243     const std::set<std::string> &templateSet = fvd->getVerbTemplateSet(infinitive_verb);
244     if (templateSet.empty())
245         return NULL;
246
247     Verbiste_TemplateArray a = new char *[templateSet.size() + 1];
248     size_t i = 0;
249     for (std::set<std::string>::const_iterator it = templateSet.begin();
250                                                it != templateSet.end(); ++it, ++i)
251         a[i] = strnew(it->c_str());
252     a[i] = NULL;
253     return a;
254 }
255
256
257 static void
258 free_string_array(char *array[])
259 {
260     if (array == NULL)
261         return;
262     for (size_t i = 0; array[i] != NULL; ++i)
263         delete [] array[i];
264     delete [] array;
265 }
266
267
268 void
269 verbiste_free_verb_template_array(Verbiste_TemplateArray array)
270 {
271     free_string_array(array);
272 }
273
274
275 Verbiste_PersonArray
276 verbiste_conjugate(const char *infinitive_verb,
277                    const char *template_name,
278                    const Verbiste_Mode mode,
279                    const Verbiste_Tense tense,
280                    int include_pronouns)
281 {
282     VVS tenseConjug;
283     if (::generateTense(tenseConjug, infinitive_verb, template_name, mode, tense,
284                                                 include_pronouns != 0) != 0)
285         return NULL;
286
287     size_t numPersons = tenseConjug.size();
288     Verbiste_PersonArray personArray =
289                                 new Verbiste_InflectionArray[numPersons + 1];
290
291     for (size_t i = 0; i < numPersons; i++)
292     {
293         const VS &inflections = tenseConjug[i];
294         size_t numInf = inflections.size();
295         Verbiste_InflectionArray infArray = new char *[numInf + 1];
296         for (size_t j = 0; j < numInf; j++)
297             infArray[j] = strnew(inflections[j]);
298         infArray[numInf] = NULL;
299         personArray[i] = infArray;
300     }
301     personArray[numPersons] = NULL;
302     return personArray;
303 }
304
305
306 void
307 verbiste_free_person_array(Verbiste_PersonArray array)
308 {
309     if (array == NULL)
310         return;
311
312     for (size_t i = 0; array[i] != NULL; i++)
313         free_string_array(array[i]);
314     delete [] array;
315 }