#include <stdio.h>

#include <string.h>


#ifndef GLOBAL_DECL

#include "global.h"     // Global data types and variables

#endif


void get_from_line(char* line, char* value)
{
    int loop, loop2;

    if ((line[0] == NULL)||(line[0] == 10)) // Empty line

    {
        line[0] = NULL;
        value[0] = NULL;    // Pass back empty string

    }
    else                // Non-empty line

    {

        strcpy( value, "" );

        // Loop through to find the first comma without an escape character

        loop = -1;
        do
        {
            loop++;

            if ( line[loop] == '\\' )
            // Excape character found, so treat next character as a normal

            // character even if it is a comma.

            {
                // Remove escape character and shift the remainder

                // of the array along.

                loop2 = loop;
                do
                {
                    line[loop2] = line[loop2+1];
                    loop2++;
                } while (line[loop2] != NULL);

                // Shift to character after escaped character

                // (unless at end of string - which SHOULDN'T happen)

                if (line[loop] != NULL)
                    loop++;
            }
        } while ( (line[loop] != ',') && (line[loop] != NULL) && (line[loop] != 10) );

        strncpy( value, line, loop );
        value[loop] = NULL;
        if (line[0] != NULL)
            strcpy( line, &line[loop+1] );
    }
}

void get_table_options(char* value, table_opts* ptropts)
{
    int     line_pos;
    char    subvalue[3];        // value extracted from initial value


    // Extract table options from string

    subvalue[0] = value[0];
    subvalue[1] = value[1];
    subvalue[2] = NULL;
    ptropts -> table_no = atoi(subvalue);
    line_pos = 2;
    if (value[2]=='-')
    {
        ptropts -> ignore_range = true;
        subvalue[0] = value[3];
        subvalue[1] = value[4];
        subvalue[2] = NULL;
        ptropts -> table_range_end = atoi(subvalue);
        line_pos = 5;
    }
    else
    {
        ptropts -> ignore_range = false;
    }
    switch (value[line_pos])
    {
        case 'I': ptropts -> ignore_table = Ignore;   break;
        case 'D': ptropts -> ignore_table = Display;  break;
        case 'A': ptropts -> ignore_table = Announce; break;
    }
}

void get_subpage_options(char* line, sub_opts* ptropts)
{
    char value[100];

    // Extract first and last link

    get_from_line( line, value );
    if (strlen(value) == 6)
    {
        ptropts -> last_link = atoi( &value[3] );
        value[3] = NULL;
        ptropts -> first_link = atoi( value );
    }
    else
    {
        ptropts -> first_link = 0;
        ptropts -> last_link = 999;
    }

    get_from_line( line, value );
    strcpy( ptropts -> filter, value );
}

pglist* ParseCategories(pglist* pagelist, config* settings)
{
    FILE*               fp;                 // file pointer

    char                line[200];          // line read from file

    char                value[100];         // value extracted from line

    data_item*          data = NULL;        // pointer to structure containing data

    table_opts*         tables = NULL;      // pointer to structure containing table options

    sub_opts*           subpages = NULL;    // pointer to structure containing subpage options

    block_opts*         blocks = NULL;      // pointer to structure containing block options

    bool                start_ignored;      // used for block options

    int                 loop;               // loop variable


    if (pagelist == NULL)
    {
        pagelist = new pglist;              // linked list with pages

    }
    else
    {
        delete pagelist;                    // delete old list

        pagelist = new pglist;              // new linked list with pages

    }

    // Open page list file for parsing

    fp = fopen("pagelist.txt", "r");
    if (fp == NULL)
    {
        printf("Page list file not found\n");
        return NULL;
    }

    // Read the version number to allow for informing user of updates

    do
    {
        fgets( settings -> version_number, 200, fp );
    } while (!(strlen(settings -> version_number) > 1));

    // Loop through page list file

    while( !feof( fp ) )
    {
        line[0] = NULL;
        fgets( line, 200, fp );

        // Lines starting with a # are treated as comments

        // Blank lines are ignored


        switch( line[0] )
        {
            case '#':       // Comment

            case '\n':      // Blank line

                break;

            case 'P':       // Page


                strcpy( line, &line[2] );   // Remove first 2 characters


                if (data == NULL)
                    data = new data_item;

                data -> selected = false;

                // Extract ID

                get_from_line( line, value );
                strcpy( data -> page_id, value );

                // Extract Description

                get_from_line( line, value );
                strcpy( data -> description, value );

                // Extract URL

                get_from_line( line, value );
                strcpy( data -> url, value );

                break;

            case 'C':       // Categories


                strcpy( line, &line[2] );   // Remove first 2 characters


                // Extract Categories

                for ( loop=0; loop<MAX_CAT_LEVELS; loop++ )
                {
                    get_from_line( line, value );
                    strcpy( data -> category[loop], value );
                }
                break;

            case 'F':       // Main page filtering settings


                strcpy( line, &line[2] );   // Remove first 2 characters


                // Extract Table Settings

                do
                {
                    get_from_line( line, value );
                    if (strlen(value)>2)
                    {
                        tables = new table_opts;
                        get_table_options(value, tables);
                        data -> table_options.insert(tables);
                    }

                } while (strlen(value)>2);

                break;

            case 'S':       // Subpage download and filtering settings


                strcpy( line, &line[2] );   // Remove first 2 characters


                // Insert previous sub page data into list if necessary

                if ((subpages != NULL) && (data != NULL))
                {
                    data -> sub_options.insert( subpages );
                }

                // Extract subpage options

                subpages = new sub_opts;

                get_subpage_options(line, subpages);

                // Extract table options for subpage

                do
                {
                    get_from_line( line, value );
                    if (strlen(value)>2)
                    {
                        tables = new table_opts;
                        get_table_options(value, tables);
                        // Insert into subpage's table options list

                        subpages -> table_options.insert(tables);
                    }

                } while (strlen(value)>2);

                break;

            case 'I':       // Block ignore options


                strcpy( line, &line[2] );   // Remove first 2 characters


                get_from_line( line, value );

                // Get whether or not the page should start in an ignored block

                start_ignored = false;
                if (strlen(value) == 1)
                    if ((value[0] == 'T') || (value[0] == 't'))
                        start_ignored = true;

                // Extract Block Options

                do
                {
                    get_from_line( line, value );

                    // Get block ignore triggers

                    if (strlen(value)>0)
                    {
                        blocks = new block_opts;
                        strcpy( blocks -> trigger_text, value );
                        blocks -> start_ignored = start_ignored;

                        // Insert block options into relevant list

                        if (subpages == NULL)
                            data -> block_options.insert(blocks);
                        else
                            subpages -> block_options.insert(blocks);
                    }

                } while (strlen(value)>0);

                break;

            case 'E':       // End of page


                // Insert page data into list if necessary

                if (data != NULL)
                {
                    // Insert sub page data into list if necessary

                    if (subpages != NULL)
                    {
                        data -> sub_options.insert( subpages );
                        subpages = NULL;
                    }

                    pagelist -> insert( data );
                    data = NULL;
                }

                break;

            default:
                break;
        }
    }

    fclose(fp);

    pagelist -> sort();

    return pagelist;
}

syntax highlighted by Code2HTML, v. 0.8.11