/* $Revision Header *** Header built automatically - do not edit! ***********
 *
 *	(C) Copyright 1993 by Rainer Koppler
 *
 *	Name .....: APCNames.c
 *	Created ..: Friday 5-Mar-93 19:31:41
 *	Revision .: 2
 *
 *	Date        Author                 Comment
 *	=========   ====================   ====================
 *	23-Mar-93   Rainer Koppler         Bug fix: multiple periods handled
 *      17-Mar-93   Rainer Koppler         Bug fix: disk entry only at root lev
 *	05-Mar-93   Rainer Koppler         Created this file!
 *
 ****************************************************************************
 *
 *      Utility for creating original file names for MS-DOS file names
 *      from the APCINFO.DAT file created by the Mac tool AccessPC.
 *
 * $Revision Header ********************************************************/

#include "APCNames.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define STUB_CHAR(x)  ((x)<0 ? '&' : (x)+'0')

/*
** SetPattern/NextEntry are my own Amiga-specific pattern-matching routines.
** I suppose there is no need for them on **IX... :^)
*/

#ifdef AMIGA
#include "Wildcard.h"
#else
static char *fnDummy;
static void  SetPattern (char *fileName)
{ 
  fnDummy = fileName;
}
static char *NextEntry (void)
{  
  char *fn = fnDummy;
  fnDummy = NULL;
  return fn;
}
#endif


/*----------------------------- global data ---------------------------------*/

static FILE *apcInfoDat;
static union APCEntry *entry;
static char lName[32],sName[13],*sPtr,*mPtr;

static const char versionStr[] = {
  "\0$VER: APCNames 1.0b by Rainer Koppler (23.3.93)"
};


/*---------------- disk entry for empty disk (view by name) -----------------*/

static ULONG de_Empty[] = {
  0x0A526169, 0x6E657220, 0x31001600, 0x0002A002,
  0x02000000, 0x00000000, 0x00000000, 0x00000001,
  0x002E0008, 0x00EA019C, 0x01000070, 0x02480200,
  0xFFF8FFF0, 0x00000000, 0x00008000, 0x00000002,
  0x7FA95F49, 0x6E736967, 0x6E696100, 0x00000000
};

/*-------------- file entries for frequently used file types ----------------*/

static ULONG fe_Default[] = {
  0x00000000, 0x00000000, 0x00000000, 0x00000000,
  0x000D0D90, 0x0000000F, 0x000000E5, 0x000D0D90,
  TYPE_TEXT, CREATOR_TTXT, 0x0100FFFF, 0xFFFF0000,
  0x00000000, 0x00000000, 0x00000000, 0x00000000,
  0x00000000, 0x00000000, 0x00000000, 0x00000000
};

static ULONG fe_ThinkPascal[] = {
  0x00000000, 0x00000000, 0x00000000, 0x00000008,
  0x0000A3F8, 0x0000000F, 0x000000E5, 0x0000A3F8,
  TYPE_TEXT, CREATOR_THINK, 0x0100FFFF, 0xFFFF0000,
  0x00000000, 0x00000000, 0x00000000, 0x00000000,
  0x00000000, 0x00000000, 0x00000000, 0x00000000
};

static ULONG fe_BBEdit[] = {
  0x00000000, 0x00000000, 0x00000000, 0x00000000,
  0x7F6A000B, 0x70A20000, 0x00022004, 0x0002B27E,
  TYPE_TEXT, CREATOR_BBEDIT, 0x0100FFFF, 0xFFFF0000,
  0x00000000, 0x00000000, 0x00000000, 0x00000000,
  0x00000000, 0x00000000, 0x00000000, 0x00000000
};


/*---------------------------------------------------------------------------*/

static void Pas2CStr (UBYTE *ps, char *cs)
{
 UBYTE len = *ps;

 strncpy(cs,ps+1,len);
 *(cs+len) = '\0';
}

/*---------------------------------------------------------------------------*/

static void C2PasStr (char *cs, UBYTE *ps)
{
 UBYTE len = strlen(cs);

 strcpy(ps+1,cs);
 *ps = len;
}

/*---------------------------------------------------------------------------*/

static void Long2Short (char *fileName, int stub)
{
  char *dotPtr,*ptr;
  ULONG *entryData;
  int i;

/*--- copy appropriate entry template to "entry" (change for your needs) ---*/
  entryData = fe_Default;
  if(dotPtr = strchr(fileName,'.')) {
    if(!strcmp(dotPtr+1,"p"))
      entryData = fe_ThinkPascal;
    else if(!strcmp(dotPtr+1,"txt") || !strcmp(dotPtr+1,"doc") ||
        !strncmp(dotPtr+1,"ad",2))
      entryData = fe_BBEdit;
  }
  memcpy(entry,entryData,APC_ENTRY_SIZE);
/*--- insert original file name ---*/
  C2PasStr(fileName,(UBYTE *)entry);
/*--- encode original file name to MS-DOS file name ---*/
  for(i=0,sPtr=sName,ptr=fileName; i<8 && *ptr!='\0' && *ptr!='.' ;
      sPtr++,ptr++,i++)
    *sPtr = toupper(*ptr);
  if(i==8 && *ptr!='.')
    *(sPtr-1) = STUB_CHAR(stub);
  if(dotPtr) {
    *sPtr = '.';
    sPtr++;
    for(i=0,ptr=dotPtr+1; i<3 && *ptr!='\0'; ptr++)
      if(*ptr != '.') {
        *sPtr = toupper(*ptr);
        sPtr++;
        i++;
      }
  }
  *sPtr = '\0';
/*--- insert MS-DOS file name into entry ---*/
  for(i=0,sPtr=sName,ptr=entry->fe.fe_MSDOSName; i<8 && *sPtr!='\0' &&
      *sPtr!='.' ;sPtr++,ptr++,i++)
    *ptr = *sPtr;
  for(; i<8; i++,ptr++)
    *ptr = ' ';
  i = 0;
  if(dotPtr)
    for(sPtr++; i<3 && *sPtr!='\0'; sPtr++,ptr++,i++)
      *ptr = toupper(*sPtr);
  for(; i<3; i++,ptr++)
    *ptr = ' ';
}

/*---------------------------------------------------------------------------*/

static void Short2Long (void)
{
  int i;

  if(entry->fe.fe_Length > 31) {
    *sName = '\0'; *lName = '\0';
    return;
  }
  Pas2CStr((UBYTE *)entry,lName);
  sPtr = sName;
  mPtr = entry->fe.fe_MSDOSName;
  for(i=0; i<8 && *mPtr!=' '; sPtr++,mPtr++,i++)
    *sPtr=*mPtr;
  mPtr = entry->fe.fe_MSDOSExt;
  if(*mPtr != ' ') {
    *sPtr = '.';
    sPtr++;
  }
  for(i=0; i<3 && *mPtr!=' '; sPtr++,mPtr++,i++)
    *sPtr=*mPtr;
  *sPtr = '\0';
}

/*---------------------------------------------------------------------------*/

static BOOL EntryExistsFor (char *fileName, int *stub)
{
  BOOL fnd = FALSE;
  char *dotPtr,*fnDot,ch;
  int newStub;

/*--- assume that no entry with same 7 first letters exists ---*/
  *stub = -1;
  fseek(apcInfoDat,0L,SEEK_SET);
  while(!fnd && fread(entry,APC_ENTRY_SIZE,1,apcInfoDat) > 0) {
    Pas2CStr((UBYTE *)entry,lName);
    fnd = !strcmp(fileName,lName);
    if(!fnd) {
      dotPtr=strchr(lName,'.');
    /*--- file name > 8 chars and same 7 first letters ->conflict ---*/
      if(dotPtr) {
        if(dotPtr-lName>8 && !strnicmp(lName,fileName,7) &&
            ((fnDot=strchr(fileName,'.')) && !stricmp(dotPtr+1,fnDot+1))) {
          if((ch = entry->fe.fe_MSDOSName[7]) == '&')
            newStub = 0;
          else
            newStub = ch-'0'+1;
          if(newStub > *stub) *stub = newStub;
        }
      }
      else {
        if(strlen(lName)>8 && !strnicmp(lName,fileName,7)) {
          if((ch = entry->fe.fe_MSDOSName[7]) == '&')
            newStub = 0;
          else
            newStub = ch-'0'+1;
          if(newStub > *stub) *stub = newStub;
        }
      }
    }
  }
  return(fnd);
}


/*---------------------------------------------------------------------------*/

main (int argc, char *argv[])
{
  int cnt,fnCnt,total,stub;
  char *fn;
  LONG fp;

  printf("\n»»APCNames«« - AccessPC renaming utility v1.0b for AmigaDOS\n\n");

  if(--argc > 0 && strcmp(argv[1],"-c")) {
    printf("USAGE: %s [ -c <file> { <file> }]\n",argv[0]);
    exit(EXIT_FAILURE);
  }

  if(!(entry=malloc(APC_ENTRY_SIZE))) {
    printf("No memory for entry block.\n");
    exit(EXIT_FAILURE);
  }

  fnCnt = 0;
  total = 0;

/*--- transform long names to short names and create/update APCINFO file ---*/
  if(argc > 0) {
    if(!(apcInfoDat=fopen("APCINFO.DAT","a+"))) {
      printf("Cannot open APCINFO.DAT for update.\n");
      exit(EXIT_FAILURE);
    }
  /*--- if new file then create (empty) disk entry at beginning ---*/
    fseek(apcInfoDat,0L,SEEK_END);
    if(ftell(apcInfoDat) == 0)
      fwrite(de_Empty,1,APC_ENTRY_SIZE,apcInfoDat);
  /*--- process arguments ---*/
    for(cnt=2; cnt<=argc; cnt++) {
      SetPattern(argv[cnt]);
      while(fn = NextEntry()) {
      /*--- lookup APCINFO.DAT for existing entry ---*/
        if(!EntryExistsFor(fn,&stub)) {
          fseek(apcInfoDat,0L,SEEK_END);
          fp = ftell(apcInfoDat);
          if(fp % 0x0400 == 0x03C0) {
            memset(entry,0,APC_PAD_SIZE);
            fwrite(entry,APC_PAD_SIZE,1,apcInfoDat);
          }
          Long2Short(fn,stub);
          fwrite(entry,APC_ENTRY_SIZE,1,apcInfoDat);
          printf("renaming \"%s\" to \"%s\"...",fn,sName);
          total++;
          if(!rename(fn,sName)) {
            printf("ok\n");
            fnCnt++;
          }
          else
            printf("failed\n");
        }
        else
          printf("\"%s\" already exists - skipped.\n",fn); 
      }
    }
    fclose(apcInfoDat);
    printf("\n%d file(s) of %d renamed successfully.\n",fnCnt,total);
  }
/*--- get contents of APCINFO file and transform short names to long names ---*/
  else {
    if(!(apcInfoDat=fopen("APCINFO.DAT","r"))) {
      printf("Cannot open APCINFO.DAT for input.\n");
      exit(EXIT_FAILURE);
    }
    cnt = 0;
    while(fread(entry,APC_ENTRY_SIZE,1,apcInfoDat) > 0) {
    /*--- D I S K  E N T R Y ---*/
      if(entry->fe.fe_MSDOSName[1] == '©') {
        Pas2CStr((UBYTE *)entry,lName);
        printf("Disk name: %s\n\n",lName);
      }
    /*--- F I L E  E N T R Y ---*/
      else {
      /*--- create MS-DOS name and original name of entry data ---*/
        Short2Long();
      /*--- rename only if valid file entry ---*/
        if(entry->fe.fe_Type == TYPE_TEXT /*&& entry->fe.fe_Flags == 0*/) {
          printf("renaming \"%s\" to \"%s\"...",sName,lName);
          total++;
          if(!rename(sName,lName)) {
            printf("ok\n");
            fnCnt++;
          }
          else
            printf("failed\n");
        }
        else
          printf("ignoring \"%s\" (\"%s\")\n",sName,lName);
      }
      cnt++;
    /*--- skip 64 bytes after each 12 records ---*/
      if(cnt == 12) {
        fread(entry,APC_PAD_SIZE,1,apcInfoDat);
        cnt = 0;
      }
    }
    fclose(apcInfoDat);
    printf("\n%d file(s) of %d renamed successfully.\n",fnCnt,total);
  }
  free(entry);
}
