/*
 *  SCHED.C - Program to read records from Poqet Address Book Application
 *
 *  This small program reads data from the file PHONE.ABD and prints
 *  data contained therein to the screen.
 *
 *  This program is released into the public domain, the author
 *  assumes no responsibility for any damage or loss caused by the
 *  use of this utiltiy.
 */

#include <stdio.h>
#include <stdlib.h>

#define CODE_CATEGORY               '\x1f'
#define CODE_NAME                   '\x1e'
#define CODE_NOTES                  '\x1c'
#define CODE_ADDR                   '\x1b'
#define CODE_PHONE                  '\x1a'
#define CODE_EOR                    '\x19'
#define CODE_EOF                    '\x18'
#define CODE_BREAK                  '\x17'

struct S_AddrRec
{
    char        cCategory;
    char *      pszName;
    char *      pszNotes;
    char *      pszAddr;
    char *      pszPhone;
};
#ifndef __cplusplus
typedef struct S_AddrRec                S_AddrRec;
#endif
typedef S_AddrRec *                     pS_AddrRec;

static void                 DumpAddrRec(pS_AddrRec pRec);
static pS_AddrRec           GetAddrRec(FILE *fp);
static char *               ReadRecord(void *pBuf, int nBufLen, FILE *fp);

static char                 Buf[2048];

int main(int argc, char **argv)
{
    auto     FILE *         fp = fopen("phone.abd", "rb");
    auto     pS_AddrRec     pRec;

    if (fp)
    {
        while (pRec = GetAddrRec(fp))
        {
            DumpAddrRec(pRec);
            free(pRec);
        }

        fclose(fp);
    }

    return(EXIT_SUCCESS);
}

static void DumpAddrRec(pS_AddrRec pRec)
{
    printf("Name: %s\nNotes: %s\nAddr: %s\nPhone: %s\n",
            pRec->pszName, pRec->pszNotes,
            pRec->pszAddr, pRec->pszPhone);
    return;
}

static pS_AddrRec GetAddrRec(FILE *fp)
{
    auto     pS_AddrRec         pRec;
    auto     char *             p;
    auto     char *             pIn;

    if (NULL == ReadRecord(Buf, sizeof(Buf), fp))
        return(NULL);

    pRec = (pS_AddrRec) malloc(sizeof(*pRec) + strlen(Buf));
    p = (char *) pRec + sizeof(*pRec);
    pIn = Buf;
    while (*pIn)
    {
        switch (*pIn)
        {
            case CODE_CATEGORY:
                pRec->cCategory = *(++pIn);
                break;

            case CODE_NAME:
                pRec->pszName = p;
                break;

            case CODE_NOTES:
                *p = 0;
                pRec->pszNotes = ++p;
                break;

            case CODE_ADDR:
                *p = 0;
                pRec->pszAddr = ++p;
                break;

            case CODE_PHONE:
                *p = 0;
                pRec->pszPhone = ++p;
                break;

            case CODE_BREAK:
                if (CODE_BREAK != *(pIn + 1))
                    *p++ = '\n';

                break;

            case CODE_EOR:
            case '\n':
                break;

            case CODE_EOF:          /* should never happen  */
                free(pRec);
                return(NULL);

            default:
                *p++ = *pIn;
                break;
        }

        ++pIn;
    }

    *p = 0;
    return(pRec);
}

static char *ReadRecord(void *pBuf, int nBufLen, FILE *fp)
{
    auto     int            c;
    auto     char *         p = pBuf;

    --nBufLen;
    while (nBufLen > 0)
    {
        c = fgetc(fp);
        if (EOF == c || CODE_EOF == c)
            return(NULL);

        if ('\r' == c || '\n' == c)
            continue;

        *p++ = c;
        --nBufLen;
        if (CODE_EOR == c)
            break;
    }

    *p = 0;
    return(pBuf);
}
