/* * Copyright (C) 2020 J. Ali Harlow * * 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 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include "pre-inst/post.h" #define PLOVER_XML_NS "http://project.juiblex.co.uk/plover/ns/2009" enum post_state { POST_STATE_BEGIN, POST_STATE_ROOT, POST_STATE_ARGUMENT, POST_STATE_INSTALL_PREFIX, POST_STATE_REPOSITORY, }; struct post_context { struct post *post; enum post_state state; int unknown_elements; GPtrArray *args; GString *str; }; static void post_start_element(void *data,const char *name,const char **atts) { struct post_context *ctx=data; if (ctx->unknown_elements) ctx->unknown_elements++; else if (ctx->state==POST_STATE_BEGIN && !strcmp(name,PLOVER_XML_NS "\xFF" "post")) ctx->state=POST_STATE_ROOT; else if (ctx->state==POST_STATE_ROOT && !strcmp(name,PLOVER_XML_NS "\xFF" "command")) { ctx->state=POST_STATE_ARGUMENT; if (ctx->args->len>0) { ctx->str=g_ptr_array_index(ctx->args,0); g_string_truncate(ctx->str,0); } else { ctx->str=g_string_new(NULL); g_ptr_array_add(ctx->args,ctx->str); } } else if (ctx->state==POST_STATE_ROOT && !strcmp(name,PLOVER_XML_NS "\xFF" "argument")) { ctx->state=POST_STATE_ARGUMENT; ctx->str=g_string_new(NULL); if (ctx->args->len==0) g_ptr_array_add(ctx->args,NULL); g_ptr_array_add(ctx->args,ctx->str); } else if (ctx->state==POST_STATE_ARGUMENT) { if (!strcmp(name,PLOVER_XML_NS "\xFF" "install-prefix")) ctx->state=POST_STATE_INSTALL_PREFIX; else if (!strcmp(name,PLOVER_XML_NS "\xFF" "repository")) ctx->state=POST_STATE_REPOSITORY; else ctx->unknown_elements++; } else ctx->unknown_elements++; } static void post_end_element(void *data,const char *name) { struct post_context *ctx=data; if (ctx->unknown_elements) ctx->unknown_elements--; else switch (ctx->state) { case POST_STATE_BEGIN: g_assert_not_reached(); break; case POST_STATE_ROOT: ctx->state=POST_STATE_BEGIN; break; case POST_STATE_ARGUMENT: ctx->state=POST_STATE_ROOT; break; case POST_STATE_INSTALL_PREFIX: if (ctx->post->install_prefix) g_string_append(ctx->str,ctx->post->install_prefix); ctx->state=POST_STATE_ARGUMENT; break; case POST_STATE_REPOSITORY: if (ctx->post->repository) g_string_append(ctx->str,ctx->post->repository); ctx->state=POST_STATE_ARGUMENT; break; } } static void post_character_data(void *data,const XML_Char *s,int len) { struct post_context *ctx=data; switch (ctx->state) { case POST_STATE_ARGUMENT: g_string_append_len(ctx->str,s,len); break; default: break; } } struct post *pre_install_post_new(const char *repository, const char *install_prefix) { struct post *post; post=g_new0(struct post,1); post->repository=g_strdup(repository); post->install_prefix=g_strdup(install_prefix); return post; } void pre_install_post_free(struct post *post) { g_free(post->repository); g_free(post->install_prefix); g_free(post); } gboolean pre_install_post_load_uri(struct post *post,const char *uri, GError **error) { int i; gboolean retval; struct post_context ctx={0,}; struct razor_error *tmp_error=NULL; size_t length; void *contents; XML_Parser parser; contents=razor_uri_get_contents(uri,&length,FALSE,&tmp_error); if (!contents) { plover_propagate_razor_error(error,tmp_error); return FALSE; } parser=XML_ParserCreateNS(NULL,'\xFF'); ctx.post=post; ctx.state=POST_STATE_BEGIN; ctx.args=g_ptr_array_new(); XML_SetUserData(parser,&ctx); XML_SetElementHandler(parser,post_start_element,post_end_element); XML_SetCharacterDataHandler(parser,post_character_data); retval=XML_Parse(parser,contents,length,TRUE)!=XML_STATUS_ERROR; if (!retval) g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED, "%s on line %lu of '%s'\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned long)XML_GetCurrentLineNumber(parser),uri); XML_ParserFree(parser); razor_uri_free_contents(contents,length); if (retval) { if (ctx.args->len>0 && !g_ptr_array_index(ctx.args,0)) g_warning("post: ignoring arguments because no command specified"); if (post->argv) g_strfreev(post->argv); if (ctx.args->len>0 && g_ptr_array_index(ctx.args,0)) { post->argc=ctx.args->len; post->argv=g_new(gchar *,post->argc+1); for(i=0;iargc;i++) post->argv[i]= g_string_free(g_ptr_array_index(ctx.args,i),FALSE); post->argv[i]=NULL; } else { post->argc=0; post->argv=g_new0(gchar *,1); } g_ptr_array_free(ctx.args,FALSE); } return retval; }