/* gcompris - wordlist.h * * Copyright (C) 2003 GCompris Developpement Team * * 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 3 of the License, 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, see . */ #include #include #include #include "gcompris.h" void gc_wordlist_dump(GcomprisWordlist *wl); /** Load a wordlist formatted xml file. It contains a list of words. * * The xml file format must be like this: * * * * * word1 * word2 * ... * * * word3 * word4 * ... * * * ... * * * * * * \param format: the xml file to load (ex: wordsgame/default-fr.xml) * If format contains $LOCALE, it will be first replaced by the current long locale * and if not found the short locale name. It support printf formating. * \param ...: additional params for the format (printf like) * * \return a new GcomprisWordlist or NULL */ GcomprisWordlist *gc_wordlist_get_from_file(const gchar *format, ...) { va_list args; gchar* xmlfilename; gchar* filename; xmlDocPtr xmldoc; xmlNodePtr wlNode; xmlNodePtr node; xmlNodePtr wordsNode; guint level; GcomprisWordlist *wordlist; xmlChar *text; GSList *words = NULL; if (!format) return NULL; va_start (args, format); filename = g_strdup_vprintf (format, args); va_end (args); xmlfilename = gc_file_find_absolute(filename); /* if the file doesn't exist */ if(!xmlfilename) { g_warning("Couldn't find file %s !", filename); g_free(filename); return NULL; } g_warning("Wordlist found %s\n", xmlfilename); xmldoc = xmlParseFile(xmlfilename); if(!xmldoc){ g_warning("Couldn't parse file %s !", xmlfilename); g_free(filename); g_free(xmlfilename); return NULL; } g_free(xmlfilename); if(/* if there is no root element */ !xmldoc->children || /* if it doesn't have a name */ !xmldoc->children->name || /* if it isn't a GCompris node */ g_strcasecmp((gchar *)xmldoc->children->name,(gchar *)"GCompris")!=0) { g_warning("No Gcompris node"); xmlFreeDoc(xmldoc); g_free(filename); return NULL; } /* there is only one element child */ wlNode = xmldoc->children->children; while((wlNode!=NULL)&&(wlNode->type!=XML_ELEMENT_NODE)) wlNode = wlNode->next; if((wlNode==NULL)|| g_strcasecmp((gchar *)wlNode->name,"Wordlist")!=0) { g_warning("No wordlist node %s", (wlNode == NULL) ? (gchar *)wlNode->name : "NULL node"); xmlFreeDoc(xmldoc); g_free(filename); return NULL; } /* ok, we can process the wordlist */ wordlist = g_malloc0(sizeof(GcomprisWordlist)); wordlist->filename = filename; /* Get name */ text = xmlGetProp ( wlNode, (const xmlChar *) "name"); if (text) { wordlist->name = g_strdup ((gchar *) text); xmlFree (text); } /* Get description */ text = xmlGetProp ( wlNode, (const xmlChar *) "description"); if (text) { wordlist->description = g_strdup ((gchar *) text); xmlFree (text); } /* Get locale */ text = xmlGetProp ( wlNode, (const xmlChar *) "locale"); if (text) { wordlist->locale = g_strdup ((gchar *) text); xmlFree (text); } /* Levels loop */ node = wlNode->children; while((node!=NULL)) { words = NULL; if (node->type!=XML_ELEMENT_NODE){ node = node->next; continue; } if (strcmp((char *)node->name,"level")!=0){ g_warning("Parsing %s error", filename); break; } wordsNode = node->children; if (wordsNode->type!=XML_TEXT_NODE){ g_warning("Parsing %s error", filename); break; } level=-1; text = xmlGetProp ( node, (const xmlChar *) "value"); if (text) { level = atoi((gchar *) text); xmlFree (text); } text = xmlNodeGetContent ( wordsNode); gc_wordlist_set_wordlist(wordlist, level, (const gchar*)text); xmlFree(text); node = node->next; } xmlFreeDoc(xmldoc); return wordlist; } void gc_wordlist_dump(GcomprisWordlist *wl) { GSList *level, *words; printf("Wordlist dump\n"); printf("filename:%s\n",wl->filename); printf("number of level:%d\n",wl->number_of_level); for(level = wl->levels_words; level; level = level->next) { printf("Level %d\n", ((LevelWordlist*)level->data)->level); printf("Words :"); for(words=((LevelWordlist*)level->data)->words; words; words=words->next) { printf(" %s", (char*)words->data); } puts(""); } } LevelWordlist*gc_wordlist_get_levelwordlist(GcomprisWordlist *wordlist, guint level) { GSList *lev_list, *list; LevelWordlist *lw; if(!wordlist) return NULL; lev_list = wordlist->levels_words; for (list = lev_list; list != NULL; list = list->next) { lw = list->data; if(lw->level == level) return lw; } return NULL; } /** get a random word from the wordlist in the given level * * \param wordlist: the wordlist * \param level: the level * * \return a newly allocated word or NULL */ gchar * gc_wordlist_random_word_get(GcomprisWordlist *wordlist, guint level) { LevelWordlist *lw; gchar *word; if(level>wordlist->number_of_level) level = wordlist->number_of_level; lw = gc_wordlist_get_levelwordlist(wordlist, level); if(!lw) return NULL; g_warning("Level : %d", lw->level); /* We got the proper level, find a random word */ word = (gchar *)g_slist_nth_data(lw->words, RAND(0, g_slist_length(lw->words)) ); g_warning("returning random word '%s'", word); return(g_strdup(word)); } static void gc_wordlist_free_level(LevelWordlist *lw) { GSList *words; if(!lw) return; for (words = lw->words; words !=NULL; words = words->next) g_free(words->data); g_slist_free(lw->words); g_free(lw); } /** call it to free a GcomprisWordlist as returned by gc_wordlist_get_from_file * * \param wordlist * */ void gc_wordlist_free(GcomprisWordlist *wordlist) { GSList *list; if(!wordlist) return; g_free ( wordlist->filename); g_free ( wordlist->description); g_free ( wordlist->locale); g_free ( wordlist->name); for ( list = wordlist->levels_words; list !=NULL; list=list->next){ LevelWordlist *lw = (LevelWordlist *)list->data; gc_wordlist_free_level(lw); } g_slist_free ( wordlist->levels_words); g_free (wordlist); } void gc_wordlist_set_wordlist(GcomprisWordlist *wordlist, guint level, const gchar*text) { LevelWordlist *lw; GSList *words=NULL; gchar **wordsArray; int i; g_warning("wordlist : add level=%d text=%s\n", level, text); /* remove level */ if((lw = gc_wordlist_get_levelwordlist(wordlist, level))) { g_warning("remove level %d", lw->level); wordlist->levels_words = g_slist_remove(wordlist->levels_words, lw); gc_wordlist_free_level(lw); wordlist->number_of_level--; } /* add new level */ wordsArray = g_strsplit_set (text, " \n\t", 0); i=0; for(i=0;wordsArray[i] != NULL; i++) if (wordsArray[i][0]!='\0' && !g_slist_find_custom(words, wordsArray[i], (GCompareFunc)strcmp)) words = g_slist_append( words, g_strdup(wordsArray[i])); g_strfreev ( wordsArray); if(words==NULL) return; /* initialise LevelWordlist struct */ LevelWordlist *level_words = g_malloc0(sizeof(LevelWordlist)); level_words->words = words; level_words->level = level; wordlist->number_of_level++; wordlist->levels_words = g_slist_append( wordlist->levels_words, level_words); } void gc_wordlist_save(GcomprisWordlist *wordlist) { GSList *listlevel,*listword; LevelWordlist *level; gchar *filename, *tmp; xmlNodePtr wlnode, levelnode, node; xmlDocPtr doc; if(!wordlist) return; doc = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION); if(!doc) return; node = xmlNewNode(NULL, BAD_CAST "GCompris"); xmlDocSetRootElement(doc,node); wlnode = xmlNewChild(node, NULL, BAD_CAST "Wordlist", NULL); if(wordlist->name) xmlSetProp(wlnode, BAD_CAST "name", BAD_CAST wordlist->name); if(wordlist->description) xmlSetProp(wlnode, BAD_CAST "description", BAD_CAST wordlist->description); if(wordlist->locale) xmlSetProp(wlnode, BAD_CAST "locale", BAD_CAST wordlist->locale); for(listlevel = wordlist->levels_words; listlevel; listlevel = listlevel->next) { level = (LevelWordlist*)listlevel->data; levelnode = xmlNewChild(wlnode, NULL, BAD_CAST "level", NULL); if((tmp = g_strdup_printf("%d", level->level))) { xmlSetProp(levelnode, BAD_CAST "value", BAD_CAST tmp); g_free(tmp); } for(listword = level->words; listword; listword=listword->next) { xmlNodeAddContent(levelnode, BAD_CAST listword->data); xmlNodeAddContent(levelnode, BAD_CAST " "); } } filename = gc_file_find_absolute_writeable(wordlist->filename); if(filename) { if(xmlSaveFormatFileEnc(filename, doc, NULL, 1)<0) { g_warning("Fail to write %s", filename); g_free(filename); } g_free(filename); } xmlFreeDoc(doc); }