// CCF = Cabernet Configuration File
// Version 4.8
// - with support for hidden panels)
// - with support for CCF version 2 (Beep and Timer actions)
 
// WANRING: only works on BIG-ENDIAN machines!!!
// (because the ccf file format is also big endian)
 
// done 1999 Markus Fritze, <http://www.markus-fritze.de/>
 
//#define NDEBUG    1 // disable assert()
#include <MacTypes.h> // SInt8, SInt16, etc.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
 
#define FNAME   "default.ccf"
 
#define CHECK_LEAKEDMEM     1
 
#pragma align_array_members off
#pragma options align=packed
typedef struct
{
  SInt32  versionPos;     // position offset to version string
  SInt32  filler1;
  char    id[8];          // = "@\245Z@_CCF";
  SInt32  crcPos;         // offset to the checksum (same like endPos)
 
  SInt16  year;
  SInt8   month;
  SInt8   day;
  SInt8   filler2;
  SInt8   hour;
  SInt8   minute;
  SInt8   seconds;
 
  SInt32  filler3;
  char    id2[4];         // = "CCF\0";
 
  SInt32  version;        // (1 = first version, 2 = with timers)
  SInt32  endPos;         // offset to the checksum (same like ptr2checksum)
  SInt32  version2;       // (version1: 60, version2: 1)
  SInt32  sysHomePos;     // offset to HOME panels
  SInt32  devPos;         // offset to first device
  SInt32  macroPos;       // offset to first macro
  SInt32  confProp;       // e.g. 0x02 = configuration is write protected
  SInt32  macroXPosV1;    // ??? (== 4 in version 2?!?)
  SInt32  macroXPosV2;    // ???
  SInt16  filler4;
} sHeaderStruct;
 
typedef struct
{
  SInt32  nextPos;        // != NULL => position of next sEntryStruct
  SInt32  namePos;
  SInt32  filler1;
  SInt32  filler2;
  SInt32  actionPos;
  SInt32  leftKeyPos;
  SInt32  rightKeyPos;
  SInt32  VolMinusKeyPos;
  SInt32  VolPlusKeyPos;
  SInt32  ChanMinusKeyPos;
  SInt32  ChanPlusKeyPos;
  SInt32  MuteKeyPos;
  SInt32  filler3;
  SInt32  leftKeyNamePos;
  SInt32  rightKeyNamePos;
  SInt32  panelsPos;
  SInt8   attr;
} sEntryStruct;
 
typedef struct
{
  SInt32  nextPos;      // != NULL => position of next sPanelStruct
  SInt32  namePos;      // name of the panel (Bit 31 is set when panel is hidden)
  SInt8   count;        // number of entries, always (?) == count2
  SInt8   count2;
  struct
  {
    SInt16  x;
    SInt16  y;
    SInt32  subPanelPos;
    SInt8   type;
  } data[];
} sPanelStruct;
 
typedef struct
{
  union
  {
    struct
    {
      SInt16    w;
      SInt16    h;
      SInt32    namePos;
      SInt32    iconPos;
      SInt32    filler;
      SInt16    attr;
      SInt16    filler2;
    } def;    // type = 0
    struct
    {
      SInt16    w;
      SInt16    h;
      SInt32    actionPos;
      SInt32    namePos;
      SInt32    filler;
      SInt16    attr;
      SInt32    icon1Pos;
      SInt32    icon2Pos;
      SInt32    icon3Pos;
      SInt32    icon4Pos;
      SInt8     inactiveUnselColor;
      SInt8     inactiveSelColor;
      SInt8     activeUnselColor;
      SInt8     activeSelColor;
    } button; // type = 1
  };
} sPanelSubStruct;
 
typedef struct
{
  SInt16    size;       // size of the structure in bytes
  SInt16    w;
  SInt16    h;
  SInt16    mode;
  char      data[];
} sIconStruct;
 
typedef struct {
  SInt8 type;         // 0x01 = CODE, 0x04 = DELAY, 0x05 = ALIAS, etc.
  SInt32  p1;
  SInt32  p2;
} sActionStruct;
 
typedef struct
{
  SInt8   count;        // number of entries, always (?) == count2
  SInt8   count2;
  sActionStruct data[];
} sActionListStruct;
 
typedef struct
{
  SInt16  size;         // size of the structure in bytes
  SInt32  namePos;
  SInt16  details;      // 0x0000 = pulse-width coding
                        // 0x0100 = pulse-position coding
                        // 0x5000 = RC5 (phase modulation)
                        // 0x5001 = RC5x (phase modulation)
                        // 0x6000 = RC6 (phase modulation)
  SInt16  carrier;
  SInt16  onceCounter;
  SInt16  repeatCounter;
  union {
    struct
    {
      SInt16  device;
      SInt16  command;
    } RC5;
    struct
    {
      SInt16  device;
      SInt16  command;
      SInt16  data;
    } RC5x;
    struct
    {
      SInt16  device;
      SInt16  command;
    } RC6;
    struct
    {
      SInt16  data[];
    } LRN;
  };
} sIRCodeStruct;
 
typedef struct
{
  SInt32  zero;
  SInt16  sDays;
  SInt16  sTime;
  SInt16  eDays;
  SInt16  eTime;
  sActionStruct sAction;
  sActionStruct eAction;
} sTimerStruct;
 
/***
 *
 ***/
const char  *gData;
#if CHECK_LEAKEDMEM
bool        *gUse;
long        gFileSize;
#endif
 
/***
 *
 ***/
static inline const char            *GetPosPtr(SInt32 pos)
{
  return reinterpret_cast<const char*>(pos + gData);
}
 
static inline const sHeaderStruct   *GetHeader(SInt32 pos)
{
  const sHeaderStruct *p = reinterpret_cast<const sHeaderStruct*>(GetPosPtr(pos));
  assert(p);
#if CHECK_LEAKEDMEM
  memset(gUse + pos, 0xFF, sizeof(sHeaderStruct));
#endif
  return p;
}
 
static inline UInt16                GetCRC(SInt32 pos)
{
#if CHECK_LEAKEDMEM
  memset(gUse + pos, 0xFF, sizeof(UInt16));
#endif
  return *reinterpret_cast<const UInt16*>(gData + pos);
}
 
static inline const sPanelStruct    *GetPanel(SInt32 pos)
{
  const sPanelStruct  *p = reinterpret_cast<const sPanelStruct*>(GetPosPtr(pos));
  assert(p);
#if CHECK_LEAKEDMEM
  memset(gUse + pos, 0xFF, sizeof(sPanelStruct) + 9 * p->count);
#endif
  return p;
}
 
static inline const sEntryStruct    *GetEntry(SInt32 pos)
{
  const sEntryStruct  *p = reinterpret_cast<const sEntryStruct*>(GetPosPtr(pos));
  assert(p);
#if CHECK_LEAKEDMEM
  memset(gUse + pos, 0xFF, sizeof(sEntryStruct));
#endif
  return p;
}
 
static inline const sActionListStruct *GetActionList(SInt32 pos)
{
  const sActionListStruct *p = reinterpret_cast<const sActionListStruct*>(GetPosPtr(pos));
  assert(p);
#if CHECK_LEAKEDMEM
  memset(gUse + pos, 0xFF, sizeof(sActionListStruct) + p->count * sizeof(sActionStruct));
#endif
  return p;
}
 
static inline const sIRCodeStruct   *GetIRCode(SInt32 pos)
{
  const sIRCodeStruct *p = reinterpret_cast<const sIRCodeStruct*>(GetPosPtr(pos));
  assert(p);
#if CHECK_LEAKEDMEM
  memset(gUse + pos, 0xFF, p->size);
#endif
  return p;
}
 
static inline const sPanelSubStruct *GetSubPanel(SInt32 pos)
{
  const sPanelSubStruct *p = reinterpret_cast<const sPanelSubStruct*>(GetPosPtr(pos));
  assert(p);
#if CHECK_LEAKEDMEM
  memset(gUse + pos, 0xFF, sizeof(sPanelSubStruct));
#endif
  return p;
}
 
static inline const sIconStruct     *GetIcon(SInt32 pos)
{
  const sIconStruct     *p = reinterpret_cast<const sIconStruct*>(GetPosPtr(pos));
  assert(p);
#if CHECK_LEAKEDMEM
  memset(gUse + pos, 0xFF, p->size);
#endif
  return p;
}
 
static inline const sTimerStruct    *GetTimerEntry(SInt32 pos)
{
  const sTimerStruct *p = reinterpret_cast<const sTimerStruct*>(GetPosPtr(pos));
  assert(p);
#if CHECK_LEAKEDMEM
  memset(gUse + pos, 0xFF, sizeof(sTimerStruct));
#endif
  return p;
}
 
// return a ptr to a _pascal_ string (first byte = length, second byte = 1. char, third byte = 2. char, etc.)
static inline const char            *GetCCFString(SInt32 pos)
{
  if(pos == 0) return reinterpret_cast<const char*>("\p<NIL>"); // illegal position => <NIL> string
 
  const char            *p = reinterpret_cast<const char*>(GetPosPtr(pos));
  assert(p);
#if CHECK_LEAKEDMEM
  memset(gUse + pos, 0xFF, p[0] + 1);
#endif
  return p;
}
 
/***
 *
 ***/
static void PrintAction(const sActionStruct *si)
{
  const sIRCodeStruct   *irs;
  const sEntryStruct    *es;
  const sPanelStruct    *ps;
  const sPanelSubStruct *pss;
  const sTimerStruct    *ts;
 
  switch(si->type)
  {
  case 0x01:  // Code
    irs = GetIRCode(si->p2);
    printf("[C] %#s ", GetCCFString(irs->namePos));
    switch(irs->details)
    {
    case 0x0100:  // pulse-position coding
        printf("(pulse-position coding)\n");
        goto cont;
    case 0x0000:  // learned
        printf("(pulse-width coding)\n");
    cont:
#if 0
        int   index;
        printf("Carrier: %x\n", irs->carrier);
        printf("Once: ");
        for(index=0; index < irs->onceCounter*2; index += 2)
          printf("%.4x/%.4x ", irs->LRN.data[index], irs->LRN.data[index+1]);
        printf("\n");
        printf("Repeat: ");
        for(int i=0; i < irs->repeatCounter*2; i += 2)
          printf("%.4x/%.4x ", irs->LRN.data[i + index], irs->LRN.data[i + index + 1]);
        printf("\n");
#endif
        break;
    case 0x5000:
        printf("%d %d\n", irs->RC5.device, irs->RC5.command);
        break;
    case 0x5001:
        printf("%d %d %d\n", irs->RC5x.device, irs->RC5x.command, irs->RC5x.data);
        break;
    case 0x6000:
        printf("%d %d\n", irs->RC6.device, irs->RC6.command);
        break;
    default:
        printf("unknown: %x\n", irs->details);
        printf("Carrier: %x\n", irs->carrier);
        printf("Once   : %x\n", irs->onceCounter);
        printf("Repeat : %x\n", irs->repeatCounter);
        break;
    }
    break;
 
  case 0x02:  // Button
    es = GetEntry(si->p1);
    if(es->namePos) printf("[B] %#s - ", GetCCFString(es->namePos));
    pss = GetSubPanel(si->p2);
    if(pss->button.namePos) printf("%#s", GetCCFString(pss->button.namePos));
    printf("\n");
    break;
 
  case 0x03:  // Jump (last possible action in a macro)
    printf("Jump: ");
    switch(si->p2)
    {
    default:
      es = GetEntry(si->p1);
      if(es->namePos) printf("%#s - ", GetCCFString(es->namePos));
      ps = GetPanel(si->p2);
      if(ps->namePos) printf("%#s", GetCCFString(ps->namePos));
      printf("\n");
      break;
    case 0xdddddddd:
      printf("Scroll down");
      break;
    case 0xEEEEEEEE:
      printf("Scroll up");
      break;
    case 0xFFFFFFFF:
      printf("Mouse mode");
      break;
    }
    printf("\n");
    break;
 
  case 0x04:  // Delay
    // p2 contains the delay in ms
    printf("[D] %.1f sec\n", float(si->p2) / 1000);
    break;
 
  case 0x05:  // Alias
    printf("[K] ");
    es = GetEntry(si->p1);
    if(es->namePos) printf("%#s - ", GetCCFString(es->namePos));
    switch(si->p2)
    {
    case 0: printf("left"); break;
    case 1: printf("right"); break;
    case 2: printf("Vol-"); break;
    case 3: printf("Vol+"); break;
    case 4: printf("Chan-"); break;
    case 5: printf("Chan+"); break;
    case 6: printf("Mute"); break;
    default:printf("unknown(%ld)", si->p2); break;
    }
    printf("\n");
    break;
 
  case 0x06:  // Jump Device
    es = GetEntry(si->p1);
    if(es->namePos) printf("[A] %#s\n", GetCCFString(es->namePos));
    break;
 
  case 0x07:  // Timer
    printf("[T] TimerAction\n");
    ts = GetTimerEntry(si->p2);
    printf("Start: ");
    PrintAction(&ts->sAction);
    static const char *dayArr[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Son", "Wkly" };
    printf("       ");
    for(long i=0x0100,j=0; i<=0x8000; i<<=1,++j)
      if(ts->sDays & i) printf("%s ", dayArr[j]);
    printf("%d:%d\n", ts->sTime / 60, ts->sTime % 60);
    printf("Stop : ");
    PrintAction(&ts->eAction);
    printf("       ");
    for(long i=0x0100,j=0; i<=0x8000; i<<=1,++j)
      if(ts->eDays & i) printf("%s ", dayArr[j]);
    printf("%d:%d\n", ts->eTime / 60, ts->eTime % 60);
    break;
 
  case 0x08:  // Beep
    SInt32  val = si->p2;
    printf("[S] %ld Hz %ld %% %ld0 ms\n", (val >> 8) & 0xFFFF, val & 0xFF, (val >> 24) & 0xFF);
    break;
 
  default:
    printf("unknown Type : %d : %ld/%lx\n", si->type, si->p1, si->p2);
    break;
  }
}
 
static void PrintActionList(ConstStr255Param name, SInt32 pos)
{
  printf("%#s: ", name);
 
  const sActionListStruct *sa = GetActionList(pos);
  for(int index=0; index<sa->count; ++index)
    PrintAction(&sa->data[index]);
}
 
/***
 *
 ***/
static void PrintIcon(SInt32 pos)
{
  const sIconStruct *si = GetIcon(pos);
#if 0
  printf("ICON(P:%lx,S:%d,W:%d,H:%d,M:%x)\n", pos, si->size, si->w, si->h, si->mode);
  // print some nice ascii art...
  const char  *dataPtr = si->data;
  int         bitOffset = (si->mode == 0x1800) ? 1 : 2; // b/w (mode == 0x1800) or 4 colors (mode == 0x0100)
  int         bitMask = (1 << bitOffset) - 1;
  const char  *bitMap = (bitOffset == 1) ? "# " : "#+. ";
  for(int h=0; h<si->h; ++h)
  {
    int   bitPos = 8 - bitOffset;
    for(int w=0; w<si->w; ++w)
    {
      putchar(bitMap[(*dataPtr >> bitPos) & bitMask]);
      bitPos -= bitOffset;
      if(bitPos < 0)
      {
        bitPos = 8 - bitOffset;
        dataPtr++;
      }
    }
    if(bitPos > 0)
      ++dataPtr;
    printf("\n");
  }
#endif
}
 
/***
 *  2 bit color index => string
 ***/
static const char   *GetColor(char color)
{
  switch(color & 3)
  {
  default:
  case 0: return "black";
  case 1: return "dkGray";
  case 2: return "ltGray";
  case 3: return "white";
  }
}
 
/***
 *  8 bit font index => string
 ***/
static const char   *GetFont(char font)
{
  switch(font)
  {
  case 0: return "<none>";
  case 1: return "Pronto 8";
  case 2: return "Pronto 10";
  case 3: return "Pronto 12";
  case 4: return "Pronto 14";
  case 5: return "Pronto 16";
  case 6: return "Pronto 18";
  default:return "Pronto xx";
  }
}
 
/***
 *
 ***/
static void PrintSubPanel(const sPanelStruct *ps, int index)
{
  assert(ps);
  const sPanelSubStruct *ps2 = GetSubPanel(ps->data[index].subPanelPos);
  switch(ps->data[index].type)
  {
  case 0:
    if(ps2->def.namePos) printf("Name : %#s\n", GetCCFString(ps2->def.namePos));
    printf("Frame:\n");
    printf("Pos  : (%d,%d)-(%d,%d)\n", ps->data[index].x, ps->data[index].y, ps2->def.w, ps2->def.h);
    printf("(Font:%s, Text;%s, Back:%s)\n", GetFont(ps2->def.attr >> 8), GetColor(ps2->def.attr), GetColor(ps2->def.attr >> 2));
    if(ps2->def.iconPos) PrintIcon(ps2->def.iconPos);
    break;
  case 1:
    if(ps2->button.namePos) printf("Name : %#s\n", GetCCFString(ps2->button.namePos));
    printf("Button:\n");
    printf("Pos  : (%d,%d)-(%d,%d)\n", ps->data[index].x, ps->data[index].y, ps2->button.w, ps2->button.h);
    printf("(Font:%s, Text;%s, Back:%s)\n", GetFont(ps2->button.attr >> 8), GetColor(ps2->button.attr), GetColor(ps2->button.attr >> 2));
    printf("(inUnCol:%s", GetColor(ps2->button.inactiveUnselColor));
    printf(", inSelCol:%s", GetColor(ps2->button.inactiveSelColor));
    printf(", actUnCol:%s", GetColor(ps2->button.activeUnselColor));
    printf(", actSelCol:%s)\n", GetColor(ps2->button.activeSelColor));
    if(ps2->button.icon1Pos) PrintIcon(ps2->button.icon1Pos);
    if(ps2->button.icon2Pos) PrintIcon(ps2->button.icon2Pos);
    if(ps2->button.icon3Pos) PrintIcon(ps2->button.icon3Pos);
    if(ps2->button.icon4Pos) PrintIcon(ps2->button.icon4Pos);
    if(ps2->button.actionPos) PrintActionList("\pAction", ps2->button.actionPos);
    break;
  }
}
 
/***
 *  Print panel with all subpanels
 ***/
static void PrintPanel(SInt32 pos)
{
  for(const sPanelStruct *ps = GetPanel(pos); ps != NULL; ps = GetPanel(ps->nextPos))
  {
    printf("Panelname : ");
    bool  isHidden = (ps->namePos & 0x80000000L) == 0x80000000L;
    if(isHidden) putchar('[');
    printf("%#s", GetCCFString(ps->namePos & 0x7FFFFFFFL));
    if(isHidden) putchar(']');
    printf("\n");
 
    for(int i=0; i<ps->count; ++i)
      PrintSubPanel(ps, i);
 
    if(ps->nextPos == NULL)
      break;
  }
}
 
/***
 *  Print an entry (device, macrolist, home, etc.) with panels
 ***/
static void PrintEntry(const sEntryStruct *dl, bool printName = true)
{
  assert(dl);
  if(printName) printf("Entryname : %#s", GetCCFString(dl->namePos));
  if(dl->attr)
  {
    printf(" (");
    bool  isPrinted = false;
    if(dl->attr & 0x40) { printf("Is Template"); isPrinted = true; }
    if(dl->attr & 0x01) { if(isPrinted) printf(","); printf("Is Read Only"); isPrinted = true; }
    if(dl->attr & 0x20) { if(isPrinted) printf(","); printf("Has Separator"); isPrinted = true; }
    printf(")");
  }
  printf("\n");
  if(dl->actionPos) PrintActionList("\pAction", dl->actionPos);
  if(dl->leftKeyPos) PrintActionList(dl->leftKeyNamePos ? StringPtr(GetCCFString(dl->leftKeyNamePos)) : "\pLeft", dl->leftKeyPos);
  if(dl->rightKeyPos) PrintActionList(dl->rightKeyNamePos ? StringPtr(GetCCFString(dl->rightKeyNamePos)) : "\pRight", dl->rightKeyPos);
  if(dl->VolMinusKeyPos) PrintActionList("\pVol-", dl->VolMinusKeyPos);
  if(dl->VolPlusKeyPos) PrintActionList("\pVol+", dl->VolPlusKeyPos);
  if(dl->ChanMinusKeyPos) PrintActionList("\pChan-", dl->ChanMinusKeyPos);
  if(dl->ChanPlusKeyPos) PrintActionList("\pChan+", dl->ChanPlusKeyPos);
  if(dl->MuteKeyPos) PrintActionList("\pMute", dl->MuteKeyPos);
  if(dl->panelsPos) PrintPanel(dl->panelsPos);
 
  puts("");
}
 
/***
 *  standard 16bit XModem CRC
 ***/
static UInt16 ComputeCrc(const char *bufptr, SInt32 count)
{
  assert(bufptr);
  UInt16  crc = 0;
  while(--count>=0)
  {
    crc ^= static_cast<UInt16>(*bufptr++) << 8;
    for(int i=0; i < 8; ++i)
    {
      if(crc & 0x8000)
        crc = (crc << 1) ^ 0x1021;
      else
        crc <<= 1;
    }
 
  }
  return crc;
}
 
/***
 *  load ccf file into ram
 ***/
static void   loadFile(const char *filename)
{
  FILE  *f = fopen(filename, "rb");
  assert(f);
  fseek(f, 0, SEEK_END);
  long  fSize = ftell(f); // get the filesize
  fseek(f, 0, SEEK_SET);
 
  // alloc memory for the ccf file
  if(gData) free(const_cast<char*>(gData));
  gData = reinterpret_cast<const char*>(malloc(fSize));
  assert(gData);
 
#if CHECK_LEAKEDMEM
  // alloc memory for used table (debugging)
  if(gUse) free(gUse);
  gUse = reinterpret_cast<bool*>(malloc(fSize));
  assert(gUse);
  memset(gUse, false, fSize);
  gFileSize = fSize;
#endif
 
  // load the ccf file into memory
  int count = fread(const_cast<char*>(gData), fSize, 1, f);
  assert(count == 1);
  fclose(f);
}
 
/***
 *
 ***/
static void   parseCCF()
{
  // get the fileheader
  const sHeaderStruct   *hs = GetHeader(0);
  assert(memcmp(hs->id, "@\245Z@_CCF", 8) == 0);
  printf("Version string: \"%#s\"\n", GetCCFString(hs->versionPos));
  printf("Modification date: %d:%.2d:%.2d %d.%d.%d\n", hs->hour, hs->minute, hs->seconds, hs->day, hs->month, hs->year);
  assert(strcmp(hs->id2, "CCF") == 0);
  if(hs->confProp & 2)
    puts("configuration is write-protected");
  if(hs->confProp & 4)
    puts("HOME panels are write-protected");
 
  // unknown values :-(
  assert(hs->filler1 == 0);
  assert(hs->filler2 == 0);
  assert(hs->filler3 == 0);
  assert(hs->filler4 == 0);
  printf("Version : %d\n", hs->version);
 
  // crc ok?
  if(GetCRC(hs->crcPos) != ComputeCrc(gData, hs->crcPos))
  {
    puts("Wrong CRC!");
    return;
  }
 
  puts("");
 
  if(hs->sysHomePos)
  {
    const sEntryStruct    *ss = GetEntry(hs->sysHomePos);
    printf("%#s:", GetCCFString(ss->namePos));
    PrintEntry(ss, false);
  }
 
  puts("");
  puts("DEVICES:");
  if(hs->devPos)
  {
    for(const sEntryStruct *dl = GetEntry(hs->devPos); dl != NULL; dl = GetEntry(dl->nextPos))
    {
      PrintEntry(dl);
      if(dl->nextPos == NULL)
        break;
    }
  }
 
  puts("");
  puts("MACRO GROUPS:");
  if(hs->macroPos)
  {
    for(const sEntryStruct *dl = GetEntry(hs->macroPos); dl != NULL; dl = GetEntry(dl->nextPos))
    {
      PrintEntry(dl);
      if(dl->nextPos == NULL)
        break;
    }
  }
 
  // ???
  if(hs->version == 1)
  {
    if(hs->macroXPosV1)
      PrintPanel(hs->macroXPosV1);
  } else {
    if(hs->macroXPosV2)
      PrintPanel(hs->macroXPosV2);
  }
}
 
/***
 *
 ***/
static void   PrintLeakedMemory()
{
#if CHECK_LEAKEDMEM
  // print all unused memory addresses (did we forget something or does ProntoEdit leak memory?)
  puts("");
  puts("leaked memory:");
  long  lastPos = -1;
  long  i;
  for(i=0; i<gFileSize; ++i)
  {
    if(gUse[i] == false)
    {
      if(lastPos < 0)
        lastPos = i;
    } else {
      if(lastPos >= 0)
      {
        if(lastPos != i-1)
          printf("%#lx-%#lx\n", lastPos, i-1);
        else
          printf("%#lx\n", lastPos);
        lastPos = -1;
      }
    }
  }
  if(lastPos >= 0)
  {
    if(lastPos != i-1)
      printf("%#lx-%#lx\n", lastPos, i-1);
    else
      printf("%#lx\n", lastPos);
  }
#endif
}
 
/***
 *
 ***/
int   main()
{
  loadFile(FNAME);
  parseCCF();
  PrintLeakedMemory();
}
 
papers/parse.cp.txt · Last modified: 2006/03/16 02:54 (external edit)
 
Recent changes RSS feed