/*
 * ALIB Rev. 1.0
 * Amiga Object Module Librarian
 * Programmed by Mike Schwartz
 *               (C)1985, MS Software, all rights reserved.
 *
 * Feel free to distribute this program on a no-charge basis.
 *
 * Use:
 *    ALIB  option  library filelist
 * Where
 *    option may be one of the following:
 *       D  =  delete object modules from library
 *       R  =  replace object modules (or add if not defined)
 *       L  =  directory of library
 *    library is the name of the library file to be created or modified.
 *       if no .lib extension is provided on the command line, it is
 *       appended.  Also note that a file library.dir is created for
 *       each library file and is managed by this program.
 *    filelist is a list of object module filenames separated by spaces
 *       or commas.  Note that if .o is not present in the filenames,
 *       .o will be appended.
 */
/* JOOP:
	1-Mrt-96  started cleaning up the source
	16-Mrt-96 added support for @filelist
*/

#include <stdio.h>
#include <fcntl.h>
#include <exec/exec.h>
/*
 * The following structure defines the records in the .dir file for
 * the library.
 */
#define  LD    struct   libdir_def
struct   libdir_def     {
   char  object_filename[80];       /* name of .o file */
   long  module_offset;             /* offset of module in .lib file */
   long  module_size;               /* size of module in bytes */
   };

/*
 * When the library is openned, each object module is read into memory
 * and managed with the following structure.
 */
#define  LL    struct   liblist_def
struct   liblist_def    {
   struct   libdir_def  dir_entry;  /* directory entry for module */
   char     *object_module;         /* actual text of module */
   LL       *next;                  /* pointer to next in list */
   };

/*
 * external functions
 */
extern   char  *malloc();
extern   long  lseek();

/*
 * Global variables
 */
LL    *objlist=NULL;                /* linked list of object modules */

char  libname[80];                  /* name of library file */
int   libfd;                        /* file descriptor for library file */
char  objname[80];                  /* name of object file */
int   objfd;                        /* file descriptor for object file */
char  dirname[80];                  /* name of directory file */
int   dirfd;                        /* file descriptor for directory file */

char  buf[512];                     /* misc buffer */
char  *temp[1000];					/* temp buffer to hold argumentlist */

char  option;                       /* user selected option */
/*
 * This function prints the help messages and exits.
 */
help() {
   printf("Use:\n");
   printf("   ALIB  option  library filelist \n");
   printf("Where\n");
   printf("   option may be one of the following:\n");
   printf("      D  =  delete object modules from library\n");
   printf("      R  =  replace object modules (or add if not defined) \n");
   printf("      L  =  directory of library\n");
   printf("   library is the name of the library file to be created or modified.\n");
   printf("      if no .lib extension is provided on the command line, it is \n");
   printf("      appended.  Also note that a file library.dir is created for\n");
   printf("      each library file and is managed by this program. \n");
   printf("   filelist is a list of object module filenames separated by spaces\n");
   printf("      or commas.  Note that if .o is not present in the filenames, \n");
   printf("      .o will be appended. \n");
   exit(1);
   }

/*
 * The following function opens the library and directory file.  If the
 * file does not exist, then the user is asked if he wants to create it.
 * If the library exists, then it is read in and built in a linked list.
 */
open_library() {
   LL    *lp;           /* pointer to module node */

   /*
    * Open the library file and directory file.
    */
   libfd = open(libname, O_RDONLY);
   if (libfd == -1) {
      /*
       * Library does not exist, prompt user for creation.
       */
return !0 ;
/*
      while (1) {
         printf("%s does not exist, create it? (Y/N): ", libname);
		fflush(stdout);
         gets(buf);
         if (buf[0] == 'y' || buf[0] == 'Y')
            return !0;
         if (buf[0] == 'n' || buf[0] == 'N') {
            printf("Alib abandoned\n");
            exit(1);
            }
         }
*/
      }
   dirfd = open(dirname, O_RDONLY);
   if (dirfd == -1) {
      printf("%s has been corrupted\n", dirname);
      printf("Alib abandoned\n");
      exit(1);
      }
   /*
    * library and directory files are open, read in the library.
    */
   while (1) {
      /*
       * Allocate a node to hold the object module.
       */
      lp = (LL *)malloc(sizeof(LL));
      if (lp == NULL) {
         printf("Not enough memory.\nAlib abandoned\n");
         exit(1);
         }
      /*
       * Check for end of file.
       */
      if (read(dirfd, (char *)&lp->dir_entry, sizeof(LD)) != sizeof(LD))
         break;
      /*
       * Allocate a buffer to hold the object file image.
       */
      lp->object_module = malloc(lp->dir_entry.module_size);
      if (lp->object_module == NULL) {
         printf("Not enough memory.\nAlib abandoned\n");
         exit(1);
         }
      /*
       * Read in the object module
       */
      if (read(libfd, lp->object_module, lp->dir_entry.module_size) != 
                 lp->dir_entry.module_size) {
         printf("Library file is corrupted.\nAlib abandoned\n");
         exit(1);
         }
      /*
       * Add module to linked list.
       */
      lp->next = objlist;
      objlist = lp;
      }
   /*
    * Library has been read in ok.  Close files and return.
    */
   close(libfd);
   close(dirfd);
/*   printf("Library file read in ok\n");*/
   }

/*
 * The following function removes an object module from the linked list
 * and frees up any memory used by it.
 */
kill_module(name)
char  *name;
{
   LL    *lp;
   LL    *lp2;

   if (objlist == NULL)
      return 0;
   strcpy(objname, name);
/*   strcat(objname, ".o");*/
   if (strcmp(objlist->dir_entry.object_filename,  objname) == 0) {
      lp = objlist->next;
      free(objlist->object_module);
      free((char *)objlist);
      objlist = lp;
      return !0;
      }
   for (lp = objlist; lp->next != NULL; lp=lp->next)
      if (strcmp(lp->next->dir_entry.object_filename, objname) == 0) {
         lp2 = lp->next;
         lp->next = lp2->next;
         free(lp2->object_module);
         free((char *)lp2);
         return !0;
         }
   return 0;
   }

/*
 * The following function
 */
add_module(name)
char  *name;
{
   LL    *lp;
   int   len;

   strcpy(objname, name);
/*   strcat(objname, ".o");*/
printf("adding %s\n", objname);

   /*
    * Open the object file
    */
   objfd = open(objname, O_RDONLY);
   if (objfd == -1) {
      printf("%s cannot be added\nAlib abandoned\n", objname);
      exit(1);
      }
   /*
    * Allocate a node to hold the file.
    */
   lp = (LL *)malloc(sizeof(LL));
   if (lp == NULL) {
      printf("Not enough memory.\nAlib abandoned\n");
      exit(1);
      }
   /*
    * Initialize it.
    */
   strcpy(lp->dir_entry.object_filename, objname);
   lp->dir_entry.module_size = lseek(objfd, 0, 2);
/*printf("module size = %d\n", lp->dir_entry.module_size);*/
   lseek(objfd, 0, 0);
   /*
    * Allocate the buffer to read the object module into.
    */
   lp->object_module = malloc(lp->dir_entry.module_size);
   if (lp->object_module == NULL) {
      printf("Not enough memory.\nAlib abandoned\n");
      exit(1);
      }
   /*
    * Read in the file.
    */
   if (read(objfd, lp->object_module, lp->dir_entry.module_size) != 
             lp->dir_entry.module_size) {
      printf("Library file is corrupted.\nAlib abandoned\n");
      exit(1);
      }
   /*
    * Add module to linked list.
    */
   lp->next = objlist;
   objlist = lp;
   /*
    * Close object file and return.
    */
   close(objfd);
/*   printf("%s added\n", name);*/
   }

/*
 * The following routine writes the library from memory and exits.
 */
close_library() {
   LL    *lp;
   long  file_position;
   long  length;

   /*
    * Open the library
    */
   libfd = open(libname, O_CREAT | O_WRONLY);
   if (libfd == -1) {
      printf("Error openning %s for output\nAlib abandoned", libname);
      exit(1);
      }
   dirfd = open(dirname, O_CREAT | O_WRONLY);
   if (dirfd == -1) {
      printf("Error openning %s for output\nAlib abandoned", dirname);
      exit(1);
      }
   /*
    * Write out the individual modules and directory records.
    */
   file_position = 0;
   for (lp = objlist; lp != NULL; lp = lp->next) {
      length = write(libfd, lp->object_module, lp->dir_entry.module_size);
      if (length != lp->dir_entry.module_size) {
         printf("Error writing to library file\nAlib abandoned\n");
         exit(1);
         }
      lp->dir_entry.module_offset = file_position;
      file_position += length;
      if (write(dirfd, (char *)&lp->dir_entry, sizeof(LD)) != sizeof(LD)) {
         printf("Error writing to directory file\nAlib abandoned\n");
         exit(1);
         }
      }
   /*
    * Close the library files
    */
   close(libfd);
   close(dirfd);
   printf("library is %ld bytes\nAlib complete\n", file_position);
   exit(0);
   }


/*
 * Main program.
 */
main(argc, argv)
int   argc;
char  *argv[];
{
   int   count;
   int i = 0;
   int filelist_flag = 0;

   printf("ALIB Rev. 1.0 \n");
   printf("Amiga Object Module Librarian\n");
   printf("Programmed by Mike Schwartz\n");
   printf("(C)1985 MS Software, all rights reserved\n");
   printf("Hacked by JvdW to be a bit more usefull for LCC\n");

   /*
    * check for command line parameters present.
    */
   if (argc < 3)
      help();
   /*
    * setup the option and filenames
    */
   option = argv[1][0];
   strcpy(libname, argv[2]);
   strcpy(dirname, argv[2]);
   strcat(libname, ".lib");
   strcat(dirname, ".dir");
   if (option == 'l' || option == 'L') {
      directory();
      exit(0);
      }
   if (option != 'd' && option != 'D' && option != 'r' && option != 'R')
      help();
/* JOOP: added option to use @filelist. */
	if(argv[3][0] == '@' && option != 'D')
	{
		FILE *infile;
		infile = fopen(&argv[3][1],"r");
		if(infile)
		{
			int j;
			j = 0;
			while(fscanf(infile,"%s",buf)!=EOF)
			{
				temp[i]=(char *)AllocVec(strlen(buf)+1,MEMF_CLEAR);
				strcpy(temp[i], buf);
				i++;
			}
			fclose(infile);
			filelist_flag = 1;
			argc = i + 3;
		}
		
	}

   /*
    * Open the library file
    */
   open_library();
   for (count = 3; count < argc; count++) {
      switch(option) {
         case 'd':
         case 'D':
            printf("deleting %s from library\n", argv[count]);
            if (!kill_module(argv[count]))
               printf("%s not defined in library\n", argv[count]);
            else
               printf("deleted.\n");
            break;
         case 'r':
         case 'R':
            if(filelist_flag)
			{
            	kill_module(temp[count-3]);
            	add_module(temp[count-3]);
            }
            else
            {
				kill_module(argv[count]);
				add_module(argv[count]);
			}
            break;
         }
      }
   close_library();
   i=0;
   while(temp[i])
      FreeVec(temp[i++]);
   }

directory() {
   LD    d_entry;
   int   count;
   int   bytes;

   dirfd = open(dirname, O_RDONLY);
   if (dirfd == -1) {
      printf("%s not found\n", dirname);
      exit(1);
      }
   printf("Directory of library %s\n", libname);
   printf("Module Name                    Size   Offset\n");
   count = bytes = 0;
   while (read(dirfd, (char *)&d_entry, sizeof(LD)) == sizeof(LD)) {
      printf("%-30.30s %-6d %-6d\n", d_entry.object_filename, 
               d_entry.module_size, d_entry.module_offset);
      count++;
      bytes += d_entry.module_size;
      }
   printf("Library consists of %d entries totalling %d bytes\n", count,
            bytes);
   close(dirfd);
   }
