T_Status C_DDI_Rituals::Parse_Index_Cell(T_XML_Node node, T_Ritual_Info * info, T_Int32U subtype) { T_Status status; status = Get_Required_Child_PCDATA(&info->level, node, "Level"); if (!x_Is_Success(status)) x_Status_Return(status); status = Get_Required_Child_PCDATA(&info->price, node, "Price"); if (!x_Is_Success(status)) x_Status_Return(status); /* If our level is '0', that's obviously nonsense so get rid of it */ if ((info->level[0] == '0') && (info->level[1] == '\0')) info->level = ""; status = Get_Required_Child_PCDATA(&info->componentcost, node, "ComponentCost"); if (!x_Is_Success(status)) x_Status_Return(status); status = Get_Required_Child_PCDATA(&info->keyskill, node, "KeySkillDescription"); if (!x_Is_Success(status)) x_Status_Return(status); x_Status_Return_Success(); }
static T_Status Append_Extension(T_Glyph_Ptr filename, T_File_Attribute attributes, T_Void_Ptr context) { long result; bool is_partial; T_Glyph_Ptr base_filename, output_folder = (T_Glyph_Ptr) context; T_XML_Node root; T_XML_Document document; T_Filename output_filename; if ((attributes & e_filetype_directory) != 0) x_Status_Return_Success(); /* Read the file in from the temporary folder as an XML document */ result = XML_Read_Document(&document, &l_data, filename); if (x_Trap_Opt(result != 0)) { Log_Message("Could not read XML document."); x_Status_Return_Success(); } /* Get the base filename to use for this file */ base_filename = strrchr(filename, DIR[0]); if (x_Trap_Opt(base_filename == NULL)) x_Status_Return(LWD_ERROR); base_filename++; if (x_Trap_Opt(*base_filename == '\0')) x_Status_Return(LWD_ERROR); /* Query and unset the artificial "partial" flag we added, so it doesn't confuse things by showing up in the real data file we're about to output. */ result = XML_Get_Document_Node(document, &root); if (x_Trap_Opt(result != 0)) x_Status_Return_Success(); is_partial = XML_Read_Boolean_Attribute(root, "ispartial"); XML_Write_Boolean_Attribute(root, "ispartial", false); /* Append any extensions to the document */ Append_Extensions(document, output_folder, base_filename, is_partial); /* Back up any existing file and write out the new one */ sprintf(output_filename, "%s" DIR "%s", output_folder, base_filename); Backup_Existing(output_filename); result = XML_Write_Document(document, output_filename, false, true); if (x_Trap_Opt(result != 0)) { Log_Message("Could not write XML document."); x_Status_Return_Success(); } XML_Destroy_Document(document); x_Status_Return_Success(); }
static T_Status Login(T_WWW internet, T_Glyph_Ptr email, T_Glyph_Ptr password, bool is_report_success) { static T_Glyph_Ptr l_last_email = NULL; static T_Glyph_Ptr l_last_password = NULL; T_Status status; T_Glyph_Ptr ptr, newline, invalid; /* Save our last email and password if given, or re-use them if we weren't passed in an email or password */ if (email != NULL) l_last_email = email; else email = l_last_email; if (password != NULL) l_last_password = password; else password = l_last_password; /* If we don't have an email or password, we can't log in */ if ((email[0] == '\0') || (password[0] == '\0')) x_Status_Return_Success(); /* Set up our arrays of name/value parameters to use for the login POST */ T_Glyph_Ptr names[] = { "email", "password" }; T_Glyph_Ptr values[] = { email, password }; /* Logging in is a simple POST of our username & password to the D&DI server */ status = WWW_HTTP_Post(internet,LOGIN_URL,x_Array_Size(names),names,values,&ptr); if (x_Trap_Opt(!x_Is_Success(status))) { Log_Message("Couldn't make login HTTP post!\n", true); x_Status_Return(status); } /* If the string 'invalid' appears in the first line of our response, it's a failed login. */ newline = strchr(ptr, '\n'); if (newline == NULL) { Log_Message("\n**** Login error - could not log in to D&D insider.\n", true); x_Status_Return(LWD_ERROR); } invalid = strstr(ptr, "invalid"); if ((invalid != NULL) && (invalid < newline)) { Log_Message("\n**** Login error - username / password not recognised.\n", true); x_Status_Return(LWD_ERROR); } Log_Message("Login succeeded.\n", is_report_success); l_is_password = true; x_Status_Return_Success(); }
T_Status C_DDI_Deities::Parse_Index_Cell(T_XML_Node node, T_Deity_Info * info, T_Int32U subtype) { T_Status status; status = Get_Required_Child_PCDATA(&info->alignment, node, "Alignment"); if (!x_Is_Success(status)) x_Status_Return(status); x_Status_Return_Success(); }
static T_Status Create_Document(T_XML_Document * document, T_XML_Node * root, T_Glyph_Ptr name, T_XML_Element * element) { T_Int32S result; T_Glyph buffer[500]; result = XML_Create_Document(document, element, false); if (x_Trap_Opt(result != 0)) { sprintf(buffer, "Could not create %s XML document.", name); Log_Message(buffer); x_Status_Return(LWD_ERROR); } result = XML_Get_Document_Node(*document, root); if (x_Trap_Opt(result != 0)) { sprintf(buffer, "Could not get %s XML document root.", name); Log_Message(buffer); x_Status_Return(LWD_ERROR); } x_Status_Return_Success(); }
T_Status C_DDI_Skills::Output_Entry(T_XML_Node root, T_Skill_Info * info) { T_Status status = LWD_ERROR; T_Int32S result; T_Glyph skill_id[UNIQUE_ID_LENGTH+1], buffer[500]; /* Generate a unique id for the class - if we can't, get out */ if (!Generate_Thing_Id(skill_id, "sk", info->name, &m_id_list)) { sprintf(buffer, "Error generating unique id for skill %s\n", info->name); Log_Message(buffer); goto cleanup_exit; } info->id = m_pool->Acquire(skill_id); /* Now that all our required information has been discerned, we can go ahead and create the node */ result = Create_Thing_Node(root, m_term, "Skill", info->name, skill_id, info->description, UNIQUENESS_UNIQUE, info->source, &info->node, info->is_partial); if (x_Trap_Opt(result != 0)) goto cleanup_exit; /* Add this skill to our internal list of skills */ Mapping_Add("skill", info->name, m_pool->Acquire(skill_id)); /* If we don't have a password, we can't get any more data */ if (info->is_partial) { status = SUCCESS; goto cleanup_exit; } /* Add a link for this skill's linked attribute */ Output_Link(info->node, "attribute", info->attribute, info, "attr"); status = SUCCESS; cleanup_exit: x_Status_Return(status); }
static T_Status Finish_Document(T_XML_Document document, T_Glyph_Ptr output_folder, T_Glyph_Ptr filename) { T_Int32S result; T_Glyph buffer[MAX_FILE_NAME+1]; sprintf(buffer, "%s" DIR "%s", output_folder, filename); Backup_Existing(buffer); /* Output the document into our output folder */ result = XML_Write_Document(document, buffer, false, true); if (x_Trap_Opt(result != 0)) { sprintf(buffer, "Could not write %s XML document.", filename); Log_Message(buffer); x_Status_Return(LWD_ERROR); } x_Status_Return_Success(); }
T_Status C_DDI_Backgrounds::Output_Entry(T_XML_Node root, T_Background_Info * info) { T_Status status = LWD_ERROR; T_Int32S result; T_Glyph background_id[UNIQUE_ID_LENGTH+1], buffer[10000]; /* Generate a unique id for the background - if we can't, get out */ if (!Generate_Thing_Id(background_id, "bg", info->name, &m_id_list)) { sprintf(buffer, "Error generating unique id for background %s\n", info->name); Log_Message(buffer); goto cleanup_exit; } info->id = m_pool->Acquire(background_id); /* Now that all our required information has been discerned, we can go ahead and create the node */ result = Create_Thing_Node(root, m_term, "Background", info->name, background_id, info->description, UNIQUENESS_UNIQUE, info->source, &info->node, info->is_partial); if (x_Trap_Opt(result != 0)) goto cleanup_exit; if ((info->type != NULL) && (info->type[0] != '\0')) Output_Tag(info->node, "BackType", info->type, info, "backtype", NULL, true, true); if ((info->campaign != NULL) && (info->campaign[0] != '\0')) Output_Tag(info->node, "BackCamp", info->campaign, info, "backcamp", NULL, true, true); Output_Options(info, true, &m_id_list, m_pool); Output_Options(info, false, &m_id_list, m_pool); /* Add this path to our internal list of backgrounds */ Mapping_Add("background", info->name, m_pool->Acquire(background_id)); status = SUCCESS; cleanup_exit: x_Status_Return(status); }
/* Note - this function should be resilient to stuff in the HTML changing, so if we don't find what we expect, we should just return successfully and not complain about it. */ T_Status C_DDI_Deities::Parse_Entry_Details(T_Glyph_Ptr contents, T_Deity_Info * info, T_Glyph_Ptr ptr, T_Glyph_Ptr checkpoint, vector<T_Deity_Info> * extras) { T_Status status; T_Glyph_Ptr end; ptr = Extract_Text(&info->flavor, m_pool, ptr, checkpoint, "<b>Type: </b>", "<br"); ptr = Extract_Text(&info->alignment, m_pool, ptr, checkpoint, "<b>Alignment :</b>", "</b><br"); ptr = Extract_Text(&info->gender, m_pool, ptr, checkpoint, "<b>Gender:</b>", "<br"); ptr = Extract_Text(&info->sphere, m_pool, ptr, checkpoint, "<b>Sphere:</b>", "<br"); ptr = Extract_Text(&info->dominion, m_pool, ptr, checkpoint, "<b>Dominion:</b>", "<br"); ptr = Extract_Text(&info->priests, m_pool, ptr, checkpoint, "<b>Priests:</b>", "<br"); ptr = Extract_Text(&info->adjective, m_pool, ptr, checkpoint, "<b>Adjective:</b>", "<br"); /* The description text appears after the end of the paragraph node */ ptr = Find_Text(ptr, "</p>", checkpoint, true, false); if (x_Trap_Opt(ptr == NULL)) x_Status_Return_Success(); end = Find_Text(ptr, "<p>", checkpoint, false, false); if (x_Trap_Opt(end == NULL)) x_Status_Return_Success(); *end = '\0'; status = Parse_Description_Text(&info->description, ptr, m_pool); if (x_Trap_Opt(!x_Is_Success(status))) x_Status_Return(status); *end = '<'; x_Status_Return_Success(); }
T_Status C_DDI_Rituals::Output_Entry(T_XML_Node root, T_Ritual_Info * info) { T_Status status = LWD_ERROR; T_Int32S result; T_Glyph_Ptr ptr, src; bool is_level; T_Glyph ritual_id[UNIQUE_ID_LENGTH+1], buffer[5000]; /* Generate a unique id for the ritual - if we can't, get out */ if (!Generate_Thing_Id(ritual_id, "rt", info->name, &m_id_list)) { sprintf(buffer, "Error generating unique id for ritual %s\n", info->name); Log_Message(buffer); goto cleanup_exit; } info->id = m_pool->Acquire(ritual_id); /* Now that all our required information has been discerned, we can go ahead and create the node */ result = Create_Thing_Node(root, m_term, "Ritual", info->name, ritual_id, info->description, UNIQUENESS_NONE, info->source, &info->node, info->is_partial); if (x_Trap_Opt(result != 0)) goto cleanup_exit; is_level = false; if (!x_Is_Digit(info->level[0])) ptr = info->level; else { is_level = true; Output_Tag(info->node, "ReqLevel", As_Int(atoi(info->level)), info); ptr = strchr(info->level, ' '); while ((ptr != NULL) && (*ptr == ' ')) ptr++; } if ((ptr != NULL) && (ptr[0] != '\0')) Output_Field(info->node, "ritLevText", ptr, info); else if (!is_level) { sprintf(buffer, "No ritual level found for ritual %s\n", info->name); Log_Message(buffer); } Output_Field(info->node, "ritCompCst", info->componentcost, info); Output_Key_Skills(info); /* If we don't have a password, we can't get any more data */ if (info->is_partial) { status = SUCCESS; goto cleanup_exit; } Split_To_Dynamic_Tags(info->node, info, info->category, ",", "RitualCat", "ritualcat"); Output_Field(info->node, "ritTime", info->time, info); if ((info->duration != NULL) && (info->duration[0] != '\0')) Output_Field(info->node, "ritLasts", info->duration, info); if (x_Is_Digit(info->price[0])) { strcpy(buffer, info->price); ptr = buffer; src = buffer; while (*src != '\0') { if (*src != ',') *ptr++ = *src; src++; } *ptr = '\0'; Output_Field(info->node, "ritPrice", As_Int(atoi(buffer)), info); } else if ((strcmp(info->price, "Unique") != 0) && (strcmp(info->price, "-") != 0) && (strcmp(info->price, "None") != 0)) { sprintf(buffer, "Invalid price '%s' found for ritual %s\n", info->price, info->name); Log_Message(buffer); goto cleanup_exit; } status = SUCCESS; cleanup_exit: x_Status_Return(status); }
/* Note - this function should be resilient to stuff in the HTML changing, so if we don't find what we expect, we should just return successfully and not complain about it. */ T_Status C_DDI_Rituals::Parse_Entry_Details(T_Glyph_Ptr contents, T_Ritual_Info * info, T_Glyph_Ptr ptr, T_Glyph_Ptr checkpoint, vector<T_Ritual_Info> * extras) { T_Status status; T_Glyph_Ptr end; T_Glyph_Ptr starts[] = { "???", }; T_Glyph_Ptr ends[] = { "<br", "</p", "</span" }; ptr = Extract_Text(&info->flavor, m_pool, ptr, checkpoint, "<span class=\"flavor\">", "</span>"); Strip_Bad_Characters(info->flavor); /* This was parsed from the index above, but we might as well grab it again here, in case there's more information */ starts[0] = "<b>Component Cost</b>:"; ptr = Extract_Text(&info->componentcost, m_pool, ptr, checkpoint, starts, x_Array_Size(starts), ends, x_Array_Size(ends)); Strip_Bad_Characters(info->componentcost); /* Although we've parsed the skill out of the index, replace it if we can - the one on the actual page has more data (e.g. "no check" info). */ starts[0] = "<b>Key Skill</b>:"; ptr = Extract_Text(&info->keyskill, m_pool, ptr, checkpoint, starts, x_Array_Size(starts), ends, x_Array_Size(ends)); Strip_Bad_Characters(info->keyskill); /* Although we've parsed the level out of the index, replace it if we can - the one on the actual page has more data. */ starts[0] = "<b>Level</b>:"; ptr = Extract_Text(&info->level, m_pool, ptr, checkpoint, starts, x_Array_Size(starts), ends, x_Array_Size(ends)); Strip_Bad_Characters(info->level); starts[0] = "<b>Category</b>:"; ptr = Extract_Text(&info->category, m_pool, ptr, checkpoint, starts, x_Array_Size(starts), ends, x_Array_Size(ends)); Strip_Bad_Characters(info->category); starts[0] = "<b>Time</b>:"; ptr = Extract_Text(&info->time, m_pool, ptr, checkpoint, starts, x_Array_Size(starts), ends, x_Array_Size(ends)); Strip_Bad_Characters(info->time); starts[0] = "<b>Duration</b>:"; ptr = Extract_Text(&info->duration, m_pool, ptr, checkpoint, starts, x_Array_Size(starts), ends, x_Array_Size(ends)); Strip_Bad_Characters(info->duration); starts[0] = "<b>Prerequisite</b>:"; ptr = Extract_Text(&info->prerequisite, m_pool, ptr, checkpoint, starts, x_Array_Size(starts), ends, x_Array_Size(ends)); Strip_Bad_Characters(info->prerequisite); /* Parse out any paragraph close tag we encounter here */ if (strnicmp(ptr, "</p>", 4) == 0) ptr += 4; /* Now parse the rest of the description - it might end in a </p> tag, or it might not! Who knows! */ end = Find_Text(ptr, "</p>", checkpoint, false, false); if (end == NULL) end = checkpoint; *end = '\0'; status = Parse_Description_Text(&info->description, ptr, m_pool); if (x_Trap_Opt(!x_Is_Success(status))) x_Status_Return(status); *end = '<'; x_Status_Return_Success(); }
T_Status C_DDI_Monsters::Output_Entry(T_XML_Node root, T_Monster_Info * info) { x_Status_Return(LWD_ERROR_NOT_IMPLEMENTED); }
static T_Status Restore_Old_File(T_Glyph_Ptr filename, T_File_Attribute attributes, T_Void_Ptr context) { T_Status status; T_Glyph_Ptr base_filename, output_folder = (T_Glyph_Ptr) context; T_Filename file_old, file_new, file_temp; T_Glyph buffer[1000]; if ((attributes & e_filetype_directory) != 0) x_Status_Return_Success(); /* Get the base filename to use for this file */ base_filename = strrchr(filename, DIR[0]); if (x_Trap_Opt(base_filename == NULL)) x_Status_Return(LWD_ERROR); base_filename++; if (x_Trap_Opt(*base_filename == '\0')) x_Status_Return(LWD_ERROR); /* Get the temporary filename we'll use for stuff */ sprintf(file_temp, "%s" DIR "temporary.ignore", output_folder); /* Get filenames for our source, and target files. The source is the one we just found; the target is that with ".saved" chopped off the end. */ sprintf(file_old, "%s" DIR "%s", output_folder, base_filename); strcpy(file_new, file_old); file_new[strlen(file_new) - strlen(BACKUP_EXTENSION)] = '\0'; sprintf(buffer, "Restoring %s...\n", base_filename); Log_Message(buffer, true); /* We want to swap the two files, so that the new is replaced by the old. */ FileSys_Delete_File(file_temp, FALSE); if (FileSys_Does_File_Exist(file_new)) { status = FileSys_Copy_File(file_temp, file_new, FALSE); if (!x_Is_Success(status)) { sprintf(buffer, "Couldn't make a backup of %s!\n", file_new); Log_Message(buffer, true); } } if (FileSys_Does_File_Exist(file_old)) { status = FileSys_Copy_File(file_new, file_old, FALSE); if (!x_Is_Success(status)) { sprintf(buffer, "Couldn't restore old file %s!\n", file_old); Log_Message(buffer, true); } } if (FileSys_Does_File_Exist(file_temp)) { status = FileSys_Copy_File(file_old, file_temp, FALSE); if (!x_Is_Success(status)) { sprintf(buffer, "Couldn't restore backup of new file %s!\n", file_new); Log_Message(buffer, true); } } FileSys_Delete_File(file_temp, FALSE); x_Status_Return_Success(); }
static T_Status Crawl_Data(bool use_cache, T_Glyph_Ptr email, T_Glyph_Ptr password, T_Filename output_folder, bool is_clear) { T_Status status; T_WWW internet = NULL; bool is_exists; T_Glyph_Ptr path_ptr; T_Filename folder; T_XML_Document doc_languages = NULL; T_XML_Document doc_wepprops = NULL; T_XML_Document doc_sources = NULL; C_Pool pool(10000000,10000000); C_DDI_Deities deities(&pool); C_DDI_Skills skills(&pool); C_DDI_Rituals rituals(&pool); C_DDI_Items items(&pool); C_DDI_Classes classes(&pool); C_DDI_Races races(&pool); C_DDI_Paragons paragons(&pool); C_DDI_Epics epics(&pool); C_DDI_Feats feats(&pool); C_DDI_Powers powers(&pool); C_DDI_Monsters monsters(&pool); C_DDI_Backgrounds backgrounds(&pool); vector<C_DDI_Common *> list; vector<C_DDI_Single_Common *> singles; /* Add all of our downloader classes to the list */ list.push_back(&deities); list.push_back(&skills); list.push_back(&rituals); list.push_back(&items); list.push_back(&classes); list.push_back(&races); list.push_back(¶gons); list.push_back(&epics); list.push_back(&feats); list.push_back(&powers); //Monsters aren't supported yet... #ifdef NOTYET list.push_back(&monsters); #endif list.push_back(&backgrounds); /* Find a temporary folder to use */ Get_Temporary_Folder(folder); path_ptr = folder + strlen(folder); /* Search for the folder and create it if it doesn't exist */ is_exists = FileSys_Does_Folder_Exist(folder); if (!is_exists) { status = FileSys_Create_Directory(folder); if (x_Trap_Opt(!x_Is_Success(status))) { Log_Message("Couldn't create temporary folder."); x_Status_Return(LWD_ERROR); } } /* If we're not using cached copies, log in to D&D insider (if we don't have a username and password, this just establishes the connection) */ if (!use_cache) { Log_Message("Connecting to server...\n", true); /* Open a connection to the server first */ status = WWW_HTTP_Open(&internet,LOGIN_URL,NULL,NULL,NULL); if (x_Trap_Opt(!x_Is_Success(status))) { Log_Message("Couldn't open connection to login server!\n", true); goto cleanup_exit; } status = Login(internet, email, password, true); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } /* If we're not using the cache, we want to make sure we have fresh copies of everything, so delete the files in our temporary folder */ if (!use_cache) { strcpy(path_ptr,"*.*"); FileSys_Delete_Files(folder); *path_ptr = '\0'; } /* Create XML documents for deities languages - the crawlers can add their own entries for these during processing */ status = Create_Document(&doc_languages, &l_language_root, "language", DTD_Get_Data()); if (!x_Is_Success(status)) goto cleanup_exit; status = Create_Document(&doc_wepprops, &l_wepprop_root, "weapon property", DTD_Get_Augmentation()); if (!x_Is_Success(status)) goto cleanup_exit; status = Create_Document(&doc_sources, &l_source_root, "source", DTD_Get_Augmentation()); if (!x_Is_Success(status)) goto cleanup_exit; /* First, download all the index pages if we need to */ if (!use_cache) { for (ddi_iter it = list.begin(); it != list.end(); ++it) { status = (*it)->Download_Index(folder, internet); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } for (single_iter it = singles.begin(); it != singles.end(); ++it) { status = (*it)->Download(folder, internet); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } } /* Read them in */ for (ddi_iter it = list.begin(); it != list.end(); ++it) { status = (*it)->Read_Index(folder); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } for (single_iter it = singles.begin(); it != singles.end(); ++it) { status = (*it)->Read(folder); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } /* Now download the rest of the content all at once NOTE: As of March 2011, there's no further content for download unless you have a password. */ if (!use_cache && l_is_password) { for (ddi_iter it = list.begin(); it != list.end(); ++it) { status = (*it)->Download_Content(folder, internet); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } /* It's possible that some downloads were screwed up due to the servers acting weirdly. If so, they were added to a failed list, so try them again */ Retry_Failed_Downloads(internet); } /* Read it in and process it */ for (ddi_iter it = list.begin(); it != list.end(); ++it) { status = (*it)->Read_Content(folder); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } /* Process all our stuff */ for (ddi_iter it = list.begin(); it != list.end(); ++it) { status = (*it)->Process(); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } for (single_iter it = singles.begin(); it != singles.end(); ++it) { status = (*it)->Process(); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } /* Post-process all our stuff - this requires it to have been output first, and puts finishing touches on everything */ for (ddi_iter it = list.begin(); it != list.end(); ++it) { status = (*it)->Post_Process(folder); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } for (single_iter it = singles.begin(); it != singles.end(); ++it) { status = (*it)->Post_Process(folder); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } /* Output our languages to the temporary folder, so we can append extensions to them later */ status = Finish_Document(doc_languages, folder, LANGUAGE_FILENAME); if (!x_Is_Success(status)) goto cleanup_exit; /* Now append any fixup extensions that are needed to compensate for the data being terrible */ Append_Extensions(folder, output_folder); /* Load the old "powers" XML document and try and copy any wizard powers out of it */ //We don't need to do this any more, but keep the code around just in case... // Fixup_Wizard_Powers(output_folder); /* Sources and weapon properties don't need any extensions, so they can go directly into the output folder - plus they're augmentation files, which aren't messed with anyway */ status = Finish_Document(doc_sources, output_folder, SOURCE_FILENAME); if (!x_Is_Success(status)) goto cleanup_exit; status = Finish_Document(doc_wepprops, output_folder, WEPPROP_FILENAME); if (!x_Is_Success(status)) goto cleanup_exit; /* wrapup everything */ cleanup_exit: l_language_root = NULL; if (doc_languages != NULL) XML_Destroy_Document(doc_languages); l_wepprop_root = NULL; if (doc_wepprops != NULL) XML_Destroy_Document(doc_wepprops); l_source_root = NULL; if (doc_sources != NULL) XML_Destroy_Document(doc_sources); if (internet != NULL) WWW_Close_Server(internet); /* Delete everything in our folder if required */ if (is_clear) { strcpy(path_ptr,"*.*"); FileSys_Delete_Files(folder); *path_ptr = '\0'; } x_Status_Return(status); }