plover/comps.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Jul 09 08:23:50 2009 +0100 (2009-07-09)
changeset 0 49fc8f60e4a5
child 38 a29623b68ca2
permissions -rw-r--r--
Initial checkin
ali@0
     1
/*
ali@0
     2
 * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
ali@0
     3
 * Copyright (C) 2008  Red Hat, Inc
ali@0
     4
 * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
ali@0
     5
 *
ali@0
     6
 * This program is free software; you can redistribute it and/or modify
ali@0
     7
 * it under the terms of the GNU General Public License as published by
ali@0
     8
 * the Free Software Foundation; either version 2 of the License, or
ali@0
     9
 * (at your option) any later version.
ali@0
    10
 *
ali@0
    11
 * This program is distributed in the hope that it will be useful,
ali@0
    12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
ali@0
    13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ali@0
    14
 * GNU General Public License for more details.
ali@0
    15
 *
ali@0
    16
 * You should have received a copy of the GNU General Public License along
ali@0
    17
 * with this program; if not, write to the Free Software Foundation, Inc.,
ali@0
    18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
ali@0
    19
 */
ali@0
    20
ali@0
    21
#include <string.h>
ali@0
    22
#include <stdio.h>
ali@0
    23
#include <errno.h>
ali@0
    24
#include <expat.h>
ali@0
    25
#include <assert.h>
ali@0
    26
#include "plover/plover.h"
ali@0
    27
ali@0
    28
/* Parse a comps.xml package group file. */
ali@0
    29
ali@0
    30
static struct comps_requirement *comps_package_requirement_new(void)
ali@0
    31
{
ali@0
    32
    struct comps_requirement *req;
ali@0
    33
    req=calloc(sizeof(*req),1);
ali@0
    34
    assert(req != NULL);
ali@0
    35
    req->type=COMPS_REQUIREMENT_OPTIONAL;
ali@0
    36
    return req;
ali@0
    37
}
ali@0
    38
ali@0
    39
static void comps_package_requirement_free_1(struct comps_requirement *req)
ali@0
    40
{
ali@0
    41
    if (req)
ali@0
    42
    {
ali@0
    43
	free(req->requires);
ali@0
    44
	free(req->name);
ali@0
    45
	free(req);
ali@0
    46
    }
ali@0
    47
}
ali@0
    48
ali@0
    49
static void comps_package_requirement_free(struct comps_requirement *req)
ali@0
    50
{
ali@0
    51
    struct comps_requirement *next;
ali@0
    52
    while(req)
ali@0
    53
    {
ali@0
    54
	next=req->next;
ali@0
    55
	comps_package_requirement_free_1(req);
ali@0
    56
	req=next;
ali@0
    57
    }
ali@0
    58
}
ali@0
    59
ali@0
    60
struct comps_group *comps_group_new(void)
ali@0
    61
{
ali@0
    62
    struct comps_group *group;
ali@0
    63
    group=calloc(sizeof(*group),1);
ali@0
    64
    assert(group != NULL);
ali@0
    65
    group->bydefault=1;
ali@0
    66
    group->uservisible=1;
ali@0
    67
    return group;
ali@0
    68
}
ali@0
    69
ali@0
    70
static void comps_group_free_1(struct comps_group *group)
ali@0
    71
{
ali@0
    72
    if (group)
ali@0
    73
    {
ali@0
    74
	free(group->id);
ali@0
    75
	free(group->name);
ali@0
    76
	free(group->description);
ali@0
    77
	comps_package_requirement_free(group->packages);
ali@0
    78
	free(group);
ali@0
    79
    }
ali@0
    80
}
ali@0
    81
static void comps_group_free(struct comps_group *group)
ali@0
    82
{
ali@0
    83
    struct comps_group *next;
ali@0
    84
    while(group)
ali@0
    85
    {
ali@0
    86
	next=group->next;
ali@0
    87
	comps_group_free_1(group);
ali@0
    88
	group=next;
ali@0
    89
    }
ali@0
    90
}
ali@0
    91
ali@0
    92
struct comps *plover_comps_new(void)
ali@0
    93
{
ali@0
    94
    struct comps *comps;
ali@0
    95
    comps=calloc(sizeof(*comps),1);
ali@0
    96
    assert(comps != NULL);
ali@0
    97
    return comps;
ali@0
    98
}
ali@0
    99
ali@0
   100
void plover_comps_free(struct comps *comps)
ali@0
   101
{
ali@0
   102
    if (comps)
ali@0
   103
    {
ali@0
   104
	free(comps->vendor);
ali@0
   105
	comps_group_free(comps->groups);
ali@0
   106
	free(comps);
ali@0
   107
    }
ali@0
   108
}
ali@0
   109
ali@0
   110
enum comps_state {
ali@0
   111
    COMPS_STATE_BEGIN,
ali@0
   112
    COMPS_STATE_ROOT,
ali@0
   113
    COMPS_STATE_GROUP,
ali@0
   114
    COMPS_STATE_GROUP_ID,
ali@0
   115
    COMPS_STATE_GROUP_NAME,
ali@0
   116
    COMPS_STATE_GROUP_DESCRIPTION,
ali@0
   117
    COMPS_STATE_GROUP_DEFAULT,
ali@0
   118
    COMPS_STATE_GROUP_USERVISIBLE,
ali@0
   119
    COMPS_STATE_GROUP_PACKAGELIST,
ali@0
   120
    COMPS_STATE_GROUP_PACKAGELIST_REQ,
ali@0
   121
};
ali@0
   122
ali@0
   123
struct comps_context {
ali@0
   124
    XML_Parser parser;
ali@0
   125
    enum comps_state state;
ali@0
   126
    int unknown_elements;
ali@0
   127
    char *vendor;
ali@0
   128
    struct comps_group *group;
ali@0
   129
    void *p;
ali@0
   130
};
ali@0
   131
ali@0
   132
static enum comps_requirement_type comps_to_requirement_type(const char *flags)
ali@0
   133
{
ali@0
   134
    if (strcmp(flags, "conditional") == 0)
ali@0
   135
	return COMPS_REQUIREMENT_CONDITIONAL;
ali@0
   136
    else if (strcmp(flags, "mandatory") == 0)
ali@0
   137
	return COMPS_REQUIREMENT_MANDATORY;
ali@0
   138
    else if (strcmp(flags, "default") == 0)
ali@0
   139
	return COMPS_REQUIREMENT_DEFAULT;
ali@0
   140
    else
ali@0
   141
	return COMPS_REQUIREMENT_OPTIONAL;
ali@0
   142
}
ali@0
   143
ali@0
   144
static void comps_start_element(void *data,const char *name,const char **atts)
ali@0
   145
{
ali@0
   146
    struct comps_context *ctx = data;
ali@0
   147
    struct comps_group *group;
ali@0
   148
    struct comps_requirement *packages;
ali@0
   149
    int i;
ali@0
   150
#if 0
ali@0
   151
    fprintf(stderr,"Starting element '");
ali@0
   152
    switch(ctx->state)
ali@0
   153
    {
ali@0
   154
	case COMPS_STATE_BEGIN:
ali@0
   155
	    fprintf(stderr,"/");
ali@0
   156
	    break;
ali@0
   157
	case COMPS_STATE_ROOT:
ali@0
   158
	    fprintf(stderr,"/comps/");
ali@0
   159
	    break;
ali@0
   160
	case COMPS_STATE_GROUP:
ali@0
   161
	    fprintf(stderr,"/comps/group/");
ali@0
   162
	    break;
ali@0
   163
	case COMPS_STATE_GROUP_ID:
ali@0
   164
	    fprintf(stderr,"/comps/group/id/");
ali@0
   165
	    break;
ali@0
   166
	case COMPS_STATE_GROUP_NAME:
ali@0
   167
	    fprintf(stderr,"/comps/group/name/");
ali@0
   168
	    break;
ali@0
   169
	case COMPS_STATE_GROUP_DESCRIPTION:
ali@0
   170
	    fprintf(stderr,"/comps/group/description/");
ali@0
   171
	    break;
ali@0
   172
	case COMPS_STATE_GROUP_DEFAULT:
ali@0
   173
	    fprintf(stderr,"/comps/group/default/");
ali@0
   174
	    break;
ali@0
   175
	case COMPS_STATE_GROUP_USERVISIBLE:
ali@0
   176
	    fprintf(stderr,"/comps/group/uservisible/");
ali@0
   177
	    break;
ali@0
   178
	case COMPS_STATE_GROUP_PACKAGELIST:
ali@0
   179
	    fprintf(stderr,"/comps/group/packagelist/");
ali@0
   180
	    break;
ali@0
   181
	case COMPS_STATE_GROUP_PACKAGELIST_REQ:
ali@0
   182
	    fprintf(stderr,"/comps/group/packagelist/packagereq/");
ali@0
   183
	    break;
ali@0
   184
ali@0
   185
    }
ali@0
   186
    for(i=0;i<ctx->unknown_elements;i++)
ali@0
   187
	fprintf(stderr,"*/");
ali@0
   188
    fprintf(stderr,"%s'\n",name);
ali@0
   189
#endif
ali@0
   190
    if (ctx->unknown_elements)
ali@0
   191
	ctx->unknown_elements++;
ali@0
   192
    else if (ctx->state==COMPS_STATE_BEGIN && !strcmp(name,"comps"))
ali@0
   193
    {
ali@0
   194
	ctx->state=COMPS_STATE_ROOT;
ali@0
   195
	for (i=0;atts[i];i+=2)
ali@0
   196
	{
ali@0
   197
	    if (!strcmp(atts[i],
ali@0
   198
	      "http://project.juiblex.co.uk/plover/ns/2009\xFFvendor"))
ali@0
   199
		ctx->vendor=strdup(atts[i+1]);
ali@0
   200
	}
ali@0
   201
    }
ali@0
   202
    else if (ctx->state==COMPS_STATE_ROOT && !strcmp(name,"group"))
ali@0
   203
    {
ali@0
   204
	ctx->state=COMPS_STATE_GROUP;
ali@0
   205
	group=comps_group_new();
ali@0
   206
	group->next=ctx->group;
ali@0
   207
	ctx->group=group;
ali@0
   208
    }
ali@0
   209
    else if (ctx->state==COMPS_STATE_GROUP && !strcmp(name,"id"))
ali@0
   210
    {
ali@0
   211
	ctx->state=COMPS_STATE_GROUP_ID;
ali@0
   212
	ctx->p=&ctx->group->id;
ali@0
   213
    }
ali@0
   214
    else if (ctx->state==COMPS_STATE_GROUP && !strcmp(name,"name"))
ali@0
   215
    {
ali@0
   216
	ctx->state=COMPS_STATE_GROUP_NAME;
ali@0
   217
	ctx->p=&ctx->group->name;
ali@0
   218
    }
ali@0
   219
    else if (ctx->state==COMPS_STATE_GROUP && !strcmp(name,"description"))
ali@0
   220
    {
ali@0
   221
	ctx->state=COMPS_STATE_GROUP_DESCRIPTION;
ali@0
   222
	ctx->p=&ctx->group->description;
ali@0
   223
    }
ali@0
   224
    else if (ctx->state==COMPS_STATE_GROUP && !strcmp(name,"default"))
ali@0
   225
    {
ali@0
   226
	ctx->state=COMPS_STATE_GROUP_DEFAULT;
ali@0
   227
	ctx->p=&ctx->group->bydefault;
ali@0
   228
    }
ali@0
   229
    else if (ctx->state==COMPS_STATE_GROUP && !strcmp(name,"uservisible"))
ali@0
   230
    {
ali@0
   231
	ctx->state=COMPS_STATE_GROUP_USERVISIBLE;
ali@0
   232
	ctx->p=&ctx->group->uservisible;
ali@0
   233
    }
ali@0
   234
    else if (ctx->state==COMPS_STATE_GROUP && !strcmp(name,"packagelist"))
ali@0
   235
	ctx->state=COMPS_STATE_GROUP_PACKAGELIST;
ali@0
   236
    else if (ctx->state==COMPS_STATE_GROUP_PACKAGELIST &&
ali@0
   237
      !strcmp(name,"packagereq"))
ali@0
   238
    {
ali@0
   239
	packages=comps_package_requirement_new();
ali@0
   240
	packages->next=ctx->group->packages;
ali@0
   241
	ctx->group->packages=packages;
ali@0
   242
	for (i=0;atts[i];i+=2)
ali@0
   243
	{
ali@0
   244
	    if (!strcmp(atts[i],"type"))
ali@0
   245
		packages->type=comps_to_requirement_type(atts[i+1]);
ali@0
   246
	    else if (!strcmp(atts[i],"requires"))
ali@0
   247
	    {
ali@0
   248
		packages->requires=strdup(atts[i+1]);
ali@0
   249
		packages->type=COMPS_REQUIREMENT_CONDITIONAL;
ali@0
   250
	    }
ali@0
   251
	}
ali@0
   252
	ctx->state=COMPS_STATE_GROUP_PACKAGELIST_REQ;
ali@0
   253
	ctx->p=&packages->name;
ali@0
   254
    }
ali@0
   255
    else
ali@0
   256
	ctx->unknown_elements++;
ali@0
   257
}
ali@0
   258
ali@0
   259
struct comps_list
ali@0
   260
{
ali@0
   261
    struct comps_list *next;
ali@0
   262
    /* body */
ali@0
   263
};
ali@0
   264
ali@0
   265
void *comps_list_reverse(void *list)
ali@0
   266
{
ali@0
   267
    struct comps_list *link=list,*prev=NULL,*next;
ali@0
   268
    while(link)
ali@0
   269
    {
ali@0
   270
	next=link->next;
ali@0
   271
	link->next=prev;
ali@0
   272
	prev=link;
ali@0
   273
	link=next;
ali@0
   274
    }
ali@0
   275
    return prev;
ali@0
   276
}
ali@0
   277
ali@0
   278
static void comps_end_element(void *data,const char *name)
ali@0
   279
{
ali@0
   280
    struct comps_context *ctx=data;
ali@0
   281
    if (ctx->unknown_elements)
ali@0
   282
	ctx->unknown_elements--;
ali@0
   283
    else
ali@0
   284
	switch (ctx->state)
ali@0
   285
	{
ali@0
   286
	    case COMPS_STATE_ROOT:
ali@0
   287
		ctx->group=comps_list_reverse(ctx->group);
ali@0
   288
		ctx->state=COMPS_STATE_BEGIN;
ali@0
   289
		break;
ali@0
   290
	    case COMPS_STATE_GROUP:
ali@0
   291
		ctx->group->packages=comps_list_reverse(ctx->group->packages);
ali@0
   292
		ctx->state=COMPS_STATE_ROOT;
ali@0
   293
		break;
ali@0
   294
	    case COMPS_STATE_GROUP_ID:
ali@0
   295
	    case COMPS_STATE_GROUP_NAME:
ali@0
   296
	    case COMPS_STATE_GROUP_DESCRIPTION:
ali@0
   297
	    case COMPS_STATE_GROUP_DEFAULT:
ali@0
   298
	    case COMPS_STATE_GROUP_USERVISIBLE:
ali@0
   299
	    case COMPS_STATE_GROUP_PACKAGELIST:
ali@0
   300
		ctx->state=COMPS_STATE_GROUP;
ali@0
   301
		break;
ali@0
   302
	    case COMPS_STATE_GROUP_PACKAGELIST_REQ:
ali@0
   303
		ctx->state=COMPS_STATE_GROUP_PACKAGELIST;
ali@0
   304
		break;
ali@0
   305
	}
ali@0
   306
#if 0
ali@0
   307
    fprintf(stderr,"Ending element '");
ali@0
   308
    switch(ctx->state)
ali@0
   309
    {
ali@0
   310
	case COMPS_STATE_BEGIN:
ali@0
   311
	    fprintf(stderr,"/");
ali@0
   312
	    break;
ali@0
   313
	case COMPS_STATE_ROOT:
ali@0
   314
	    fprintf(stderr,"/comps/");
ali@0
   315
	    break;
ali@0
   316
	case COMPS_STATE_GROUP:
ali@0
   317
	    fprintf(stderr,"/comps/group/");
ali@0
   318
	    break;
ali@0
   319
	case COMPS_STATE_GROUP_ID:
ali@0
   320
	    fprintf(stderr,"/comps/group/id/");
ali@0
   321
	    break;
ali@0
   322
	case COMPS_STATE_GROUP_NAME:
ali@0
   323
	    fprintf(stderr,"/comps/group/name/");
ali@0
   324
	    break;
ali@0
   325
	case COMPS_STATE_GROUP_DESCRIPTION:
ali@0
   326
	    fprintf(stderr,"/comps/group/description/");
ali@0
   327
	    break;
ali@0
   328
	case COMPS_STATE_GROUP_DEFAULT:
ali@0
   329
	    fprintf(stderr,"/comps/group/default/");
ali@0
   330
	    break;
ali@0
   331
	case COMPS_STATE_GROUP_USERVISIBLE:
ali@0
   332
	    fprintf(stderr,"/comps/group/uservisible/");
ali@0
   333
	    break;
ali@0
   334
	case COMPS_STATE_GROUP_PACKAGELIST:
ali@0
   335
	    fprintf(stderr,"/comps/group/packagelist/");
ali@0
   336
	    break;
ali@0
   337
	case COMPS_STATE_GROUP_PACKAGELIST_REQ:
ali@0
   338
	    fprintf(stderr,"/comps/group/packagelist/packagereq/");
ali@0
   339
	    break;
ali@0
   340
ali@0
   341
    }
ali@0
   342
    {
ali@0
   343
	int i;
ali@0
   344
	for(i=0;i<ctx->unknown_elements;i++)
ali@0
   345
	    fprintf(stderr,"*/");
ali@0
   346
    }
ali@0
   347
    fprintf(stderr,"%s'\n",name);
ali@0
   348
#endif
ali@0
   349
}
ali@0
   350
ali@0
   351
static void comps_character_data(void *data,const XML_Char *s,int len)
ali@0
   352
{
ali@0
   353
    struct comps_context *ctx=data;
ali@0
   354
    char *str;
ali@0
   355
    switch (ctx->state)
ali@0
   356
    {
ali@0
   357
	case COMPS_STATE_GROUP_ID:
ali@0
   358
	case COMPS_STATE_GROUP_NAME:
ali@0
   359
	case COMPS_STATE_GROUP_DESCRIPTION:
ali@0
   360
	case COMPS_STATE_GROUP_PACKAGELIST_REQ:
ali@0
   361
	    *(char **)ctx->p=str=malloc(len+1);
ali@0
   362
	    memcpy(str,s,len);
ali@0
   363
	    str[len]='\0';
ali@0
   364
	    break;
ali@0
   365
	case COMPS_STATE_GROUP_DEFAULT:
ali@0
   366
	case COMPS_STATE_GROUP_USERVISIBLE:
ali@0
   367
	    *(int *)ctx->p=*s=='T'||*s=='t';
ali@0
   368
	    break;
ali@0
   369
    }
ali@0
   370
}
ali@0
   371
ali@0
   372
#define XML_BUFFER_SIZE 4096
ali@0
   373
ali@0
   374
struct comps *plover_comps_new_from_file(const char *filename)
ali@0
   375
{
ali@0
   376
    struct comps_context ctx={0};
ali@0
   377
    void *buf;
ali@0
   378
    int len;
ali@0
   379
    FILE *fp;
ali@0
   380
    XML_ParsingStatus status;
ali@0
   381
    struct comps *comps;
ali@0
   382
    fp=fopen(filename,"r");
ali@0
   383
    if (!fp)
ali@0
   384
	return NULL;
ali@0
   385
    ctx.state=COMPS_STATE_BEGIN;
ali@0
   386
    ctx.parser=XML_ParserCreateNS(NULL,'\xFF');
ali@0
   387
    XML_SetUserData(ctx.parser,&ctx);
ali@0
   388
    XML_SetElementHandler(ctx.parser,comps_start_element,comps_end_element);
ali@0
   389
    XML_SetCharacterDataHandler(ctx.parser,comps_character_data);
ali@0
   390
    do
ali@0
   391
    {
ali@0
   392
	XML_GetParsingStatus(ctx.parser,&status);
ali@0
   393
	switch (status.parsing)
ali@0
   394
	{
ali@0
   395
	    case XML_SUSPENDED:
ali@0
   396
		XML_ResumeParser(ctx.parser);
ali@0
   397
		break;
ali@0
   398
	    case XML_PARSING:
ali@0
   399
	    case XML_INITIALIZED:
ali@0
   400
		buf=XML_GetBuffer(ctx.parser,XML_BUFFER_SIZE);
ali@0
   401
		len=fread(buf,1,XML_BUFFER_SIZE,fp);
ali@0
   402
		if (len<0)
ali@0
   403
		{
ali@0
   404
		    comps_group_free(ctx.group);
ali@0
   405
		    XML_ParserFree(ctx.parser);
ali@0
   406
		    fclose(fp);
ali@0
   407
		    return NULL;
ali@0
   408
		}
ali@0
   409
		if (!XML_ParseBuffer(ctx.parser,len,!len))
ali@0
   410
		{
ali@0
   411
		    comps_group_free(ctx.group);
ali@0
   412
		    XML_ParserFree(ctx.parser);
ali@0
   413
		    fclose(fp);
ali@0
   414
		    return NULL;
ali@0
   415
		}
ali@0
   416
		break;
ali@0
   417
	    case XML_FINISHED:
ali@0
   418
		break;
ali@0
   419
	}
ali@0
   420
    } while (status.parsing!=XML_FINISHED);
ali@0
   421
    XML_ParserFree(ctx.parser);
ali@0
   422
    fclose(fp);
ali@0
   423
    comps=plover_comps_new();
ali@0
   424
    comps->vendor=ctx.vendor;
ali@0
   425
    comps->groups=ctx.group;
ali@0
   426
    return comps;
ali@0
   427
}
ali@0
   428
ali@0
   429
struct comps_group *plover_comps_lookup_group(struct comps *comps,
ali@0
   430
  const char *id)
ali@0
   431
{
ali@0
   432
    struct comps_group *group;
ali@0
   433
    for(group=comps->groups;group;group=group->next)
ali@0
   434
	if (!strcmp(group->id,id))
ali@0
   435
	    return group;
ali@0
   436
    return NULL;
ali@0
   437
}