(linenum→info "unix/slp.c:2238")

dbus/1.0.2/bus/config-loader-expat.c

    1: /* -*- mode: C; c-file-style: "gnu" -*- */
    2: /* config-loader-expat.c  expat XML loader
    3:  *
    4:  * Copyright (C) 2003 Red Hat, Inc.
    5:  *
    6:  * Licensed under the Academic Free License version 2.1
    7:  *
    8:  * This program is free software; you can redistribute it and/or modify
    9:  * it under the terms of the GNU General Public License as published by
   10:  * the Free Software Foundation; either version 2 of the License, or
   11:  * (at your option) any later version.
   12:  *
   13:  * This program is distributed in the hope that it will be useful,
   14:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   15:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16:  * GNU General Public License for more details.
   17:  *
   18:  * You should have received a copy of the GNU General Public License
   19:  * along with this program; if not, write to the Free Software
   20:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   21:  *
   22:  */
   23: 
   24: #include "config-parser.h"
   25: #include <dbus/dbus-internals.h>
   26: #include <expat.h>
   27: 
   28: static XML_Memory_Handling_Suite memsuite =
   29: {
   30:   dbus_malloc,
   31:   dbus_realloc,
   32:   dbus_free
   33: };
   34: 
   35: typedef struct
   36: {
   37:   BusConfigParser *parser;
   38:   const char *filename;
   39:   DBusString content;
   40:   DBusError *error;
   41:   dbus_bool_t failed;
   42: } ExpatParseContext;
   43: 
   44: static dbus_bool_t
   45: process_content (ExpatParseContext *context)
   46: {
   47:   if (context->failed)
   48:     return FALSE;
   49: 
   50:   if (_dbus_string_get_length (&context->content) > 0)
   51:     {
   52:       if (!bus_config_parser_content (context->parser,
   53:                                       &context->content,
   54:                                       context->error))
   55:         {
   56:           context->failed = TRUE;
   57:           return FALSE;
   58:         }
   59:       _dbus_string_set_length (&context->content, 0);
   60:     }
   61: 
   62:   return TRUE;
   63: }
   64: 
   65: static void
   66: expat_StartElementHandler (void            *userData,
   67:                            const XML_Char  *name,
   68:                            const XML_Char **atts)
   69: {
   70:   ExpatParseContext *context = userData;
   71:   int i;
   72:   char **names;
   73:   char **values;
   74: 
   75:   /* Expat seems to suck and can't abort the parse if we
   76:    * throw an error. Expat 2.0 is supposed to fix this.
   77:    */
   78:   if (context->failed)
   79:     return;
   80: 
   81:   if (!process_content (context))
   82:     return;
   83: 
   84:   /* "atts" is key, value, key, value, NULL */
   85:   for (i = 0; atts[i] != NULL; ++i)
   86:     ; /* nothing */
   87: 
   88:   _dbus_assert (i % 2 == 0);
   89:   names = dbus_new0 (char *, i / 2 + 1);
   90:   values = dbus_new0 (char *, i / 2 + 1);
   91: 
   92:   if (names == NULL || values == NULL)
   93:     {
   94:       dbus_set_error (context->error, DBUS_ERROR_NO_MEMORY, NULL);
   95:       context->failed = TRUE;
   96:       dbus_free (names);
   97:       dbus_free (values);
   98:       return;
   99:     }
  100: 
  101:   i = 0;
  102:   while (atts[i] != NULL)
  103:     {
  104:       _dbus_assert (i % 2 == 0);
  105:       names [i / 2] = (char*) atts[i];
  106:       values[i / 2] = (char*) atts[i+1];
  107: 
  108:       i += 2;
  109:     }
  110: 
  111:   if (!bus_config_parser_start_element (context->parser,
  112:                                         name,
  113:                                         (const char **) names,
  114:                                         (const char **) values,
  115:                                         context->error))
  116:     {
  117:       dbus_free (names);
  118:       dbus_free (values);
  119:       context->failed = TRUE;
  120:       return;
  121:     }
  122: 
  123:   dbus_free (names);
  124:   dbus_free (values);
  125: }
  126: 
  127: static void
  128: expat_EndElementHandler (void           *userData,
  129:                          const XML_Char *name)
  130: {
  131:   ExpatParseContext *context = userData;
  132: 
  133:   if (!process_content (context))
  134:     return;
  135: 
  136:   if (!bus_config_parser_end_element (context->parser,
  137:                                       name,
  138:                                       context->error))
  139:     {
  140:       context->failed = TRUE;
  141:       return;
  142:     }
  143: }
  144: 
  145: /* s is not 0 terminated. */
  146: static void
  147: expat_CharacterDataHandler (void           *userData,
  148:                             const XML_Char *s,
  149:                             int             len)
  150: {
  151:   ExpatParseContext *context = userData;
  152:   if (context->failed)
  153:     return;
  154: 
  155:   if (!_dbus_string_append_len (&context->content,
  156:                                 s, len))
  157:     {
  158:       dbus_set_error (context->error, DBUS_ERROR_NO_MEMORY, NULL);
  159:       context->failed = TRUE;
  160:       return;
  161:     }
  162: }
  163: 
  164: 
  165: BusConfigParser*
  166: bus_config_load (const DBusString      *file,
  167:                  dbus_bool_t            is_toplevel,
  168:                  const BusConfigParser *parent,
  169:                  DBusError             *error)
  170: {
  171:   XML_Parser expat;
  172:   const char *filename;
  173:   BusConfigParser *parser;
  174:   ExpatParseContext context;
  175:   DBusString dirname;
  176:   
  177:   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  178: 
  179:   parser = NULL;
  180:   expat = NULL;
  181:   context.error = error;
  182:   context.failed = FALSE;
  183: 
  184:   filename = _dbus_string_get_const_data (file);
  185: 
  186:   if (!_dbus_string_init (&context.content))
  187:     {
  188:       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  189:       return NULL;
  190:     }
  191: 
  192:   if (!_dbus_string_init (&dirname))
  193:     {
  194:       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  195:       _dbus_string_free (&context.content);
  196:       return NULL;
  197:     }
  198:   
  199:   expat = XML_ParserCreate_MM ("UTF-8", &memsuite, NULL);
  200:   if (expat == NULL)
  201:     {
  202:       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  203:       goto failed;
  204:     }
  205: 
  206:   if (!_dbus_string_get_dirname (file, &dirname))
  207:     {
  208:       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  209:       goto failed;
  210:     }
  211:   
  212:   parser = bus_config_parser_new (&dirname, is_toplevel, parent);
  213:   if (parser == NULL)
  214:     {
  215:       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  216:       goto failed;
  217:     }
  218:   context.parser = parser;
  219: 
  220:   XML_SetUserData (expat, &context);
  221:   XML_SetElementHandler (expat,
  222:                          expat_StartElementHandler,
  223:                          expat_EndElementHandler);
  224:   XML_SetCharacterDataHandler (expat,
  225:                                expat_CharacterDataHandler);
  226: 
  227:   {
  228:     DBusString data;
  229:     const char *data_str;
  230: 
  231:     if (!_dbus_string_init (&data))
  232:       {
  233:         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  234:         goto failed;
  235:       }
  236: 
  237:     if (!_dbus_file_get_contents (&data, file, error))
  238:       {
  239:         _dbus_string_free (&data);
  240:         goto failed;
  241:       }
  242: 
  243:     data_str = _dbus_string_get_const_data (&data);
  244: 
  245:     if (!XML_Parse (expat, data_str, _dbus_string_get_length (&data), TRUE))
  246:       {
  247:         if (context.error != NULL &&
  248:             !dbus_error_is_set (context.error))
  249:           {
  250:             enum XML_Error e;
  251: 
  252:             e = XML_GetErrorCode (expat);
  253:             if (e == XML_ERROR_NO_MEMORY)
  254:               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  255:             else
  256:               dbus_set_error (error, DBUS_ERROR_FAILED,
  257:                               "Error in file %s, line %d, column %d: %s\n",
  258:                               filename,
  259:                               XML_GetCurrentLineNumber (expat),
  260:                               XML_GetCurrentColumnNumber (expat),
  261:                               XML_ErrorString (e));
  262:           }
  263: 
  264:         _dbus_string_free (&data);
  265:         goto failed;
  266:       }
  267: 
  268:     _dbus_string_free (&data);
  269: 
  270:     if (context.failed)
  271:       goto failed;
  272:   }
  273: 
  274:   if (!bus_config_parser_finished (parser, error))
  275:     goto failed;
  276: 
  277:   _dbus_string_free (&dirname);
  278:   _dbus_string_free (&context.content);
  279:   XML_ParserFree (expat);
  280: 
  281:   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  282:   return parser;
  283: 
  284:  failed:
  285:   _DBUS_ASSERT_ERROR_IS_SET (error);
  286: 
  287:   _dbus_string_free (&dirname);
  288:   _dbus_string_free (&context.content);
  289:   if (expat)
  290:     XML_ParserFree (expat);
  291:   if (parser)
  292:     bus_config_parser_unref (parser);
  293:   return NULL;
  294: }
Syntax (Markdown)