/*
**==============================================================================
**
** 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 <base/strings.h>
#include <base/list.h>
#include <base/io.h>
#include "regfile.h"
// Parse an identifies of the form "[A-Za-z_][A-Za-z_0-9]*"
static int _ParseIdentifier(char** pOut, char** start, char** end)
{
char* p = *pOut;
/* Skip leading whitespace */
while (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 (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"
static int _ParseClassPath(char** pOut, char** start, char** end)
{
char* p = *pOut;
/* Skip leading whitespace */
while (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 (isalnum((unsigned char)(*p)) || *p == '_' || *p == ':')
p++;
/* Set end of identifier */
*end = p;
*pOut = p;
return 0;
}
static int _ExpectChar(char** pOut, char ch)
{
char* p = *pOut;
/* Skip whitespace */
while (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'
static int _ParseKeyValueLine(char** pOut, char** keyOut, char** 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 (isspace((unsigned char)(*p)))
p++;
/* Set value */
*valueOut = p;
*pOut = p;
return 0;
}
static int _ParseClassValue(
char** pOut,
char** nameOut,
char** refName1Out,
char** refName2Out)
{
char* p = *pOut;
char* start;
char* end;
/* Expect class name */
if (_ParseClassPath(&p, &start, &end) != 0)
return -1;
/* Skip whitespace */
while (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;
}
RegFile* RegFile_New(const char* path)
{
FILE* is;
char buf[1024];
int foundLibrary = 0;
char* hosting = NULL;
RegFile* self = 0;
/* Open the file */
is = Fopen(path, "rb");
if (!is)
return NULL;
/* Allocate self structure */
self = (RegFile*)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 comment lines */
if (*p == '#')
continue;
/* Remove trailing whitespace */
{
char* end = buf + strlen(buf);
while (end != start && isspace((unsigned char)end[-1]))
*--end = '\0';
}
/* Skip leading whitespace */
while (isspace((unsigned char)(*p)))
p++;
/* 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 = Strdup(value);
if (!self->library)
goto failed;
foundLibrary = 1;
}
else if (strcmp(key, "HOSTING") == 0)
{
if (hosting)
free(hosting);
hosting = Strdup(value);
}
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*)calloc(1, sizeof(RegClass));
if (!rc)
goto failed;
List_Append(
(ListElem**)&self->classesHead,
(ListElem**)&self->classesTail,
(ListElem*)rc);
rc->name = Strdup(name);
if (!rc->name)
goto failed;
if (refName1)
{
rc->refName1 = Strdup(refName1);
if (!rc->refName1)
goto failed;
}
if (refName2)
{
rc->refName2 = Strdup(refName2);
if (!rc->refName2)
goto failed;
}
if (hosting)
rc->hosting = Strdup(hosting);
}
}
if (hosting)
free(hosting);
fclose(is);
return self;
failed:
if (self)
RegFile_Delete(self);
if (is)
fclose(is);
return NULL;
}
void RegFile_Delete(RegFile* self)
{
RegClass* rc;
RegClass* next;
if (!self)
return;
if (self->library)
free(self->library);
for (rc = self->classesHead; rc; rc = next)
{
if (rc->name)
free(rc->name);
if (rc->refName1)
free(rc->refName1);
if (rc->refName2)
free(rc->refName2);
if (rc->hosting)
free(rc->hosting);
next = rc->next;
free(rc);
}
free(self);
}
void RegFile_Print(RegFile* self, FILE* os)
{
RegClass* rc;
fprintf(os, "LIBRARY=%s\n", self->library);
for (rc = self->classesHead; rc; rc = rc->next)
{
fprintf(os, "CLASS=%s", rc->name);
if (rc->refName1 && rc->refName2)
{
fprintf(os, "{");
fprintf(os, "%s", rc->refName1);
fprintf(os, ",");
fprintf(os, "%s", rc->refName2);
fprintf(os, "}");
}
fprintf(os, "\n");
}
}