(file) Return to regfile.c CVS log (file) (dir) Up to [OMI] / omi / provreg

File: [OMI] / omi / provreg / regfile.c (download)
Revision: 1.3, Mon Apr 20 17:19:56 2015 UTC (9 years ago) by krisbash
Branch: MAIN
CVS Tags: OMI_1_0_8_2, OMI_1_0_8_1, HEAD
Changes since 1.2: +228 -60 lines
OMI 1.0.8-1

/*
**==============================================================================
**
** Open Management Infrastructure (OMI)
**
** Copyright (c) Microsoft Corporation
** 
** Licensed under the Apache License, Version 2.0 (the "License"); you may not 
** use this file except in compliance with the License. You may obtain a copy 
** of the License at 
**
**     http://www.apache.org/licenses/LICENSE-2.0 
**
** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
** MERCHANTABLITY OR NON-INFRINGEMENT. 
**
** See the Apache 2 License for the specific language governing permissions 
** and limitations under the License.
**
**==============================================================================
*/

#include <stdio.h>
#include <ctype.h>
#include <pal/strings.h>
#include <base/list.h>
#include <pal/format.h>
#include <pal/file.h>
#include <base/log.h>
#include "regfile.h"

#define REG_INDICATION_CLASS "INDICATIONCLASS"

// Parse an identifies of the form "[A-Za-z_][A-Za-z_0-9]*"
_Return_type_success_(return == 0)
static int _ParseIdentifier(_Inout_ CharPtr* pOut, _Out_ CharPtr* start, _Out_ CharPtr* end)
{
    char* p = *pOut;

    /* Skip leading whitespace */
    while (*p && isspace((unsigned char)(*p)))
        p++;

    /* Set start of identifier */
    *start = p;

    /* Expect [A-Za-z_] characters */
    if (!isalpha((unsigned char)(*p)) && *p != '_')
        return -1;

    /* Skip [A-Za-z_0-9] characters */
    while (*p && (isalnum((unsigned char)(*p)) || *p == '_'))
        p++;

    /* Set end of identifier */
    *end = p;

    *pOut = p;
    return 0;
}

// Parase class path of the form "CLASS1:CLASS2:CLASS3"
_Return_type_success_(return == 0)
static int _ParseClassPath(_Inout_ CharPtr* pOut, _Out_ CharPtr* start, _Out_ CharPtr* end)
{
    char* p = *pOut;

    /* Skip leading whitespace */
    while (*p && isspace((unsigned char)(*p)))
        p++;

    /* Set start of identifier */
    *start = p;

    /* Expect [A-Za-z_] characters */
    if (!isalpha((unsigned char)(*p)) && *p != '_')
        return -1;

    /* Skip [A-Za-z_0-9] characters */
    while (*p && (isalnum((unsigned char)(*p)) || *p == '_' || *p == ':'))
        p++;

    /* Set end of identifier */
    *end = p;

    *pOut = p;
    return 0;
}

_Return_type_success_(return == 0)
static int _ExpectChar(_Inout_ CharPtr* pOut, char ch)
{
    char* p = *pOut;

    /* Skip whitespace */
    while (*p && isspace((unsigned char)(*p)))
        p++;

    /* Expect character */
    if (*p != ch)
        return -1;
    p++;

    *pOut = p;
    return 0;
}

// Parse a line of the form 'KEY=VALUE'
_Return_type_success_(return == 0)
static int _ParseKeyValueLine(_Inout_ CharPtr* pOut, _Out_ CharPtr* keyOut, _Out_ CharPtr* valueOut)
{
    char* p = *pOut;
    char* keyEnd;

    /* Parse key */
    if (_ParseIdentifier(&p, keyOut, &keyEnd) != 0)
        return-1;

    /* If out of input, error out */
    if (!*p)
        return -1;

    /* Skip whitespace */
    if (_ExpectChar(&p, '=') != 0)
        return -1;

    /* Null-terminate the key */
    *keyEnd = '\0';

    /* Skip whitespace */
    while (*p && isspace((unsigned char)(*p)))
        p++;

    /* Set value */
    *valueOut = p;

    *pOut = p;
    return 0;
}

/*
 * Parses <value> from `*CLASS=<value>` of the forms from .reg file:
 * 1. `<ClassPath>`                             (Non-Association class)
 * 2. `<ClassPath>{<ClassPath>,<ClassPath>}`    (Association class)
 */
_Return_type_success_(return == 0)
static int _ParseClassValue(
    _Inout_ CharPtr* pOut, 
    _Out_ CharPtr* nameOut, 
    _Out_ CharPtr* refName1Out,
    _Out_ CharPtr* refName2Out)
{
    char* p = *pOut;
    char* start;
    char* end;

    /* Expect class name */
    if (_ParseClassPath(&p, &start, &end) != 0)
        return -1;

    /* Skip whitespace */
    while (*p && isspace((unsigned char)(*p)))
        p++;

    /* If end of line */
    if (!*p)
    {
        *nameOut = start;
        *end = '\0';
        *refName1Out = NULL;
        *refName2Out = NULL;
        *pOut = p;
        return 0;
    }

    /* Expect '{' character */
    if (_ExpectChar(&p, '{') != 0)
        return -1;

    /* Get 'name' */
    *nameOut = start;
    *end = '\0';

    /* Expect reference name */
    if (_ParseClassPath(&p, &start, &end) != 0)
        return -1;

    /* Expect ',' character */
    if (_ExpectChar(&p, ',') != 0)
        return -1;

    /* Get 'refName1' */
    *refName1Out = start;
    *end = '\0';

    /* Expect reference name */
    if (_ParseClassPath(&p, &start, &end) != 0)
        return -1;

    /* Expect '}' character */
    if (_ExpectChar(&p, '}') != 0)
        return -1;

    /* Get 'refName1' */
    *refName2Out = start;
    *end = '\0';

    *pOut = p;
    return 0;
}



/* Parse indication class from reg file */
_Return_type_success_(return == 0)
int ParseIndicationClass(
    _Inout_ CharPtr* pOut,
    _Inout_ RegFile* self,
    _In_opt_z_ char* hosting,
    _In_ ProvRegType type)
{
#ifdef DISABLE_INDICATION
    /* Ignore indication classes */
    MI_UNUSED(pOut);
    MI_UNUSED(self);
    MI_UNUSED(hosting);
    MI_UNUSED(type);
    return 0;
#else /* ifndef DISABLE_INDICATION */
    char* name = NULL;
    char* refName1 = NULL;
    char* refName2 = NULL;
    RegClass* rc;

    if (_ParseClassValue(pOut, &name, &refName1, &refName2) != 0)
    {
        trace_RegFile_ParseIndication_ClassValueFailed();
        return -1;
    }

    rc = (RegClass*)PAL_Calloc(1, sizeof(RegClass));
    if (!rc)
    {
        trace_RegFile_AllocFailure();
        return -1;
    }

    List_Append(
        (ListElem**)&self->classesHead,
        (ListElem**)&self->classesTail,
        (ListElem*)rc);

    if (refName1 || refName2)
    {
        trace_RegFile_IndicationClassCannotHaveRefClass();
        return -1;
    }

    rc->name = PAL_Strdup(name);
    if (!rc->name)
    {
        trace_RegFile_OutOfMemory_Name();
        return -1;
    }

    if (hosting)
    {
        rc->hosting = PAL_Strdup(hosting);
        if(!rc->hosting)
        {
            trace_RegFile_OutOfMemory_Hosting();
            return -1;
        }
    }
    rc->regtype = type;
    return 0;
#endif /* ifndef DISABLE_INDICATION */
}


RegFile* RegFile_New(const char* path)
{
    FILE* is;
    char buf[MAX_LINE];
    int foundLibrary = 0;
    char* hosting = NULL;
    RegFile* self = 0;

    /* Open the file */
    is = File_Open(path, "rb");
    if (!is)
        return NULL;

    /* Allocate self structure */
    self = (RegFile*)PAL_Calloc(1, sizeof(RegFile));
    if (!self)
    {
        fclose(is);
        return NULL;
    }

    /* Read line by line */
    while (fgets(buf, sizeof(buf), is) != NULL)
    {
        char* start = buf;
        char* p = start;
        char* key;
        char* value;

        /* Skip leading whitespace */
        while (*p && isspace((unsigned char)(*p)))
            p++;

        /* Skip comment lines */
        if (*p == '#')
            continue;

        /* Remove trailing whitespace */
        {
            char* end = buf + strlen(buf);

            while (end != start && isspace((unsigned char)end[-1]))
                *--end = '\0';
        }
               
        /* Skip blank lines */
        if (*p == '\0')
            continue;

        /* Look for LIBRARY= */
        if (_ParseKeyValueLine(&p, &key, &value) != 0)
            goto failed;

        if (strcmp(key, "LIBRARY") == 0)
        {
            if (foundLibrary)
                goto failed;

            self->library = PAL_Strdup(value);

            if (!self->library)
                goto failed;

            foundLibrary = 1;
        }
        else if (strcmp(key, "HOSTING") == 0)
        {
            if (hosting)
                PAL_Free(hosting);

            hosting = PAL_Strdup(value);
        }
        else if (strcmp(key, "INSTANCELIFETIME") == 0)
        {
            if (strcmp(value, "CONTEXT") == 0)
            {
                self->instanceLifetimeContext = 1;
            }
            else
            {
                goto failed;
            }
        }
#if defined(CONFIG_ENABLE_PREEXEC)
        else if (strcmp(key, "PREEXEC") == 0)
        {
            self->preexec = PAL_Strdup(value);
        }
#endif /* defined(CONFIG_ENABLE_PREEXEC) */
        else if (strcmp(key, "CLASS") == 0)
        {
            char* name;
            char* refName1;
            char* refName2;
            RegClass* rc;

            if (_ParseClassValue(&p, &name, &refName1, &refName2) != 0)
                goto failed;

            rc = (RegClass*)PAL_Calloc(1, sizeof(RegClass));
            if (!rc)
                goto failed;

            List_Append(
                (ListElem**)&self->classesHead,
                (ListElem**)&self->classesTail,
                (ListElem*)rc);

            rc->name = PAL_Strdup(name);
            if (!rc->name)
                goto failed;

            if (refName1)
            {
                rc->refName1 = PAL_Strdup(refName1);
                if (!rc->refName1)
                    goto failed;
            }

            if (refName2)
            {
                rc->refName2 = PAL_Strdup(refName2);
                if (!rc->refName2)
                    goto failed;
            }

            if (hosting)
            {
                rc->hosting = PAL_Strdup(hosting);
                if(!rc->hosting)
                    goto failed;
            }
        }
        else if (strcmp(key, "EXTRACLASS") == 0)
        {
            char* name;
            char* refName1;
            char* refName2;
            RegClass* rc;

            if (_ParseClassValue(&p, &name, &refName1, &refName2) != 0)
                goto failed;

            rc = (RegClass*)PAL_Calloc(1, sizeof(RegClass));
            if (!rc)
                goto failed;

            List_Append(
                (ListElem**)&self->extraClassesHead,
                (ListElem**)&self->extraClassesTail,
                (ListElem*)rc);

            rc->name = PAL_Strdup(name);
            if (!rc->name)
                goto failed;

            /* no need to use refName1, refName2 as the definition of these classes will be present as part of CLASSES list or EXTRACLASSES list */

            if (hosting)
            {
                rc->hosting = PAL_Strdup(hosting);
                if(!rc->hosting)
                    goto failed;
            }
        }
        else if (strcmp(key, REG_INDICATION_CLASS) == 0)
        {
            int r = ParseIndicationClass(&p, self, hosting, PROVREG_INDICATION);
            if (r == -1)
                goto failed;
        }
    }

    if (hosting)
        PAL_Free(hosting);

    /*If LIBRARY was not found (That should NOT happen),
    which means that this regfile is corrupted (The user might have modified it by hand). So go to failed*/
    if(!foundLibrary)
    {
        trace_RegFile_MissingLibraryTag(path);
        goto failed;
    }

    fclose(is);

    return self;

failed:
    if (self)
        RegFile_Delete(self);

    if (is)
        fclose(is);

    return NULL;
}

static void _RegClassList_Delete(RegClass *regClassHead)
{
    RegClass* rc;
    RegClass* next;
    
    for(rc = regClassHead; rc; rc = next)
    {
        if (rc->name)
            PAL_Free(rc->name);
        
        if (rc->refName1)
            PAL_Free(rc->refName1);
        
        if (rc->refName2)
            PAL_Free(rc->refName2);
        
        if (rc->hosting)
            PAL_Free(rc->hosting);
        
        next = rc->next;
        PAL_Free(rc);
    }
}

void RegFile_Delete(RegFile* self)
{
    if (!self)
        return;

    if (self->library)
        PAL_Free(self->library);

#if defined(CONFIG_ENABLE_PREEXEC)

    if (self->preexec)
        PAL_Free(self->preexec);

#endif /* defined(CONFIG_ENABLE_PREEXEC) */

    _RegClassList_Delete(self->classesHead);
    _RegClassList_Delete(self->extraClassesHead);

    PAL_Free(self);
}

void RegFile_Print(RegFile* self, FILE* os)
{
    RegClass* rc;

    Ftprintf(os, ZT("LIBRARY=%s\n"), scs(self->library));

#if defined(CONFIG_ENABLE_PREEXEC)

    Ftprintf(os, ZT("PREEXEC=%s\n"), scs(self->preexec));

#endif /* defined(CONFIG_ENABLE_PREEXEC) */

    for (rc = self->classesHead; rc; rc = rc->next)
    {
        Ftprintf(os, ZT("CLASS=%s"), scs(rc->name));

        if (rc->refName1 && rc->refName2)
        {
            Ftprintf(os, ZT("{"));
            Ftprintf(os, ZT("%s"), scs(rc->refName1));
            Ftprintf(os, ZT(","));
            Ftprintf(os, ZT("%s"), scs(rc->refName2));
            Ftprintf(os, ZT("}"));
        }

        Ftprintf(os, ZT("\n"));
    }
}

ViewCVS 0.9.2