		/*************************************
		 *                                   *
		 *             Editor v1.0           *
		 *   by Torsten Jürgeleit in 09/91   *
		 *                                   *
		 *              Load part            *
		 *                                   *
		 *************************************/

	/* Includes */

#include "includes.h"
#include "defines.h"
#include "imports.h"
#include "protos.h"

	/* Defines */

#define MAX_READ_BUFFER_SIZE	2000
#define MAX_LINE_LEN		80

#define BLOCK_TYPE_NONE		0
#define BLOCK_TYPE_HEADER	1
#define BLOCK_TYPE_TEMPLATE	2
#define BLOCK_TYPE_BOX		3
#define BLOCK_TYPE_TEXTATTR	4
#define BLOCK_TYPE_TEXTLIST	5
#define BLOCK_TYPE_BORDERDATA	6
#define BLOCK_TYPE_TEXTDATA	7
#define BLOCK_TYPE_GADGETDATA	8

#define HEADER_ITEM_TYPE_LEFTEDGE	1
#define HEADER_ITEM_TYPE_TOPEDGE	2
#define HEADER_ITEM_TYPE_WIDTH		3
#define HEADER_ITEM_TYPE_HEIGHT		4
#define HEADER_ITEM_TYPE_FLAGS		5

#define TEMPLATE_ITEM_TYPE_NAME		1
#define TEMPLATE_ITEM_TYPE_TYPE		2
#define TEMPLATE_ITEM_TYPE_FLAGS	3

#define BOX_ITEM_TYPE_X1		1
#define BOX_ITEM_TYPE_Y1		2
#define BOX_ITEM_TYPE_X2		3
#define BOX_ITEM_TYPE_Y2		4

#define TEXTATTR_ITEM_TYPE_NAME		1
#define TEXTATTR_ITEM_TYPE_YSIZE	2
#define TEXTATTR_ITEM_TYPE_STYLE	3
#define TEXTATTR_ITEM_TYPE_FLAGS	4

#define TEXTLIST_ITEM_TYPE_TEXT		1

#define BORDERDATA_ITEM_TYPE_TYPE	1

#define TEXTDATA_ITEM_TYPE_TYPE		1
#define TEXTDATA_ITEM_TYPE_FLAGS	2
#define TEXTDATA_ITEM_TYPE_TEXT		3

#define GADGETDATA_ITEM_TYPE_TYPE	1
#define GADGETDATA_ITEM_TYPE_FLAGS	2
#define GADGETDATA_ITEM_TYPE_TEXT	3
#define GADGETDATA_ITEM_TYPE_SPECIAL1	4
#define GADGETDATA_ITEM_TYPE_SPECIAL2	5
#define GADGETDATA_ITEM_TYPE_SPECIAL3	6

	/* Statics */

STATIC struct TemplateList  new_template_list;
STATIC struct Template      *new_template;

STATIC BYTE *block_keywords[] = {
	"PROJECTHEADER",
	"TEMPLATE",
	"BOX",
	"TEXTATTR",
	"TEXTLIST",
	"BORDERDATA",
	"TEXTDATA",
	"GADGETDATA",
	NULL
};
STATIC BYTE *header_keywords[] = {
	"LEFTEDGE",
	"TOPEDGE",
	"WIDTH",
	"HEIGHT",
	"FLAGS",
	NULL
};
STATIC BYTE *template_keywords[] = {
	"NAME",
	"TYPE",
	"FLAGS",
	NULL
};
STATIC BYTE *box_keywords[] = {
	"X1",
	"Y1",
	"X2",
	"Y2",
	NULL
};
STATIC BYTE *textattr_keywords[] = {
	"NAME",
	"YSIZE",
	"STYLE",
	"FLAGS",
	NULL
};
STATIC BYTE *textlist_keywords[] = {
	"TEXT",
	NULL
};
STATIC BYTE *borderdata_keywords[] = {
	"TYPE",
	NULL
};
STATIC BYTE *textdata_keywords[] = {
	"TYPE",
	"FLAGS",
	"TEXT",
	NULL
};
STATIC BYTE *gadgetdata_keywords[] = {
	"TYPE",
	"FLAGS",
	"TEXT",
	"SPECIAL1",
	"SPECIAL2",
	"SPECIAL3",
	NULL
};
	/* Load project */

   SHORT
load_project(USHORT mode)
{
   struct TemplateList   *tl = &template_list, *new_tl = &new_template_list;
   struct Template       *tp;
   struct FileRequester  *freq = project_file_requester;
   struct FileData       *fd;
   BYTE   path[LONG_DSIZE + LONG_FSIZE + 1];
   USHORT len;
   SHORT  status = EDITOR_STATUS_NORMAL;

   /* Display ARP file requester and check if user selected cancel */
   freq->fr_FuncFlags &= ~FRF_DoColor;
   if (mode == LOAD_MODE_NORMAL) {
      freq->fr_Hail = PROJECT_LOAD_HAIL_TEXT;
   } else {
      freq->fr_Hail = PROJECT_APPEND_HAIL_TEXT;
   }
   if (FileRequest(freq)) {

      /* Prepare file name and project name */
      len = strlen(freq->fr_File) - 4;
      if (Strcmp(freq->fr_File + len, ".tpl")) {
	 strcat(freq->fr_File, ".tpl");
      }
      if (mode == LOAD_MODE_NORMAL) {
	 strncpy(&new_tl->tl_ProjectName[0], freq->fr_File, (size_t)len);
	 new_tl->tl_ProjectName[len] = '\0';
      }

      /* Build full path for project file */
      strcpy(&path[0], freq->fr_Dir);
      TackOn(&path[0], freq->fr_File);

      /* Open file and write project header */
      if (!(fd = open_file(&path[0]))) {
	 status = EDITOR_ERROR_OPEN_FAILED;
      } else {

	 /* Init new template list */
	 NewList(&new_tl->tl_List);
	 new_tl->tl_ListEntries     = 0;
	 new_tl->tl_BorderTemplates = 0;
	 new_tl->tl_TextTemplates   = 0;
	 new_tl->tl_GadgetTemplates = 0;
	 new_tl->tl_Flags           = DEFAULT_TEMPLATE_LIST_FLAGS;

	 /* Read all templates */
	 while ((status = parse_block(fd, BLOCK_TYPE_NONE, mode)) ==
						      EDITOR_STATUS_NORMAL);
	 /* If no error then install and display new template list */
	 if (status == EDITOR_STATUS_EOF) {
	    if (mode == LOAD_MODE_NORMAL) {

	       /* Overwrite old template list */
	       if ((status = new_project(new_tl->tl_Flags)) ==
						     EDITOR_STATUS_NORMAL) {
		  CopyMem((BYTE *)new_tl, (BYTE *)tl, (LONG)
					       sizeof(struct TemplateList));
		  /* Copy templates from new to original template list */
		  NewList(&tl->tl_List);
		  while (tp = (struct Template *)RemHead(&new_tl->tl_List)) {
		     AddTail(&tl->tl_List, &tp->tp_Node);
		     display_template(tp);
		  }
		  tl->tl_Flags &= ~TEMPLATE_LIST_FLAG_CHANGED;
	       }
	    } else {

	       /* Append new template list to old one */
	       while (tp = (struct Template *)RemHead(&new_tl->tl_List)) {
		  AddTail(&tl->tl_List, &tp->tp_Node);
		  tl->tl_ListEntries++;
		  tl->tl_Flags |= TEMPLATE_LIST_FLAG_CHANGED;
		  display_template(tp);
		  switch (TEMPLATE_GROUP(tp)) {
		     case TEMPLATE_GROUP_BORDER :
			tp->tp_GroupEntryNum = ++tl->tl_BorderTemplates;
			break;

		     case TEMPLATE_GROUP_TEXT :
			tp->tp_GroupEntryNum = ++tl->tl_TextTemplates;
			break;

		     case TEMPLATE_GROUP_GADGET :
			tp->tp_GroupEntryNum = ++tl->tl_GadgetTemplates;
			break;
		  }
		  if (tp->tp_Flags & TEMPLATE_FLAG_DEFAULT_NAME) {
		     build_default_template_name(tp);
		  }
       	       }
	    }
	    ISetGadgetAttributes(egl, EDITOR_GADGET_TEMPLATES, 0L,
			USE_CURRENT_VALUE, USE_CURRENT_VALUE, &tl->tl_List);
	 }
	 close_file(fd);
      }
   }
   if (status != EDITOR_STATUS_NORMAL) {
      show_error(status);
   }
   return(status);
}
	/* Parse block of load file */

   STATIC SHORT
parse_block(struct FileData  *fd, USHORT block_type, USHORT mode)
{
   struct TemplateList  *tl;
   struct Template      *tp;
   struct Box           *box;
   struct BorderData    *bd;
   struct TextData      *td;
   struct GadgetData    *gd;
   BYTE  c, *keyword, *arg;
   SHORT status = EDITOR_STATUS_NORMAL;

   if (block_type == BLOCK_TYPE_TEMPLATE) {
      if (!(new_template = AllocMem((LONG)sizeof(struct Template),
					 (LONG)MEMF_PUBLIC | MEMF_CLEAR))) {
	 status = EDITOR_ERROR_OUT_OF_MEM;
      } else {

	 /* Init new template */
	 tp = new_template;
	 NewList(&tp->tp_TextList);
	 tp->tp_Node.ln_Name = &tp->tp_TemplateName[0];
      }
   }
   if (status == EDITOR_STATUS_NORMAL) {

      /* Block loop */
      do {
	 if ((status = read_line(fd)) == EDITOR_STATUS_NORMAL) {

	    /* Mark end of keyword */
	    keyword = arg = fd->fd_LineBuffer;
	    while ((c = *arg++) != ' ' && c != '=' && c != '\0');
	    if (c == '\0') {
	       status = EDITOR_ERROR_NO_ARGUMENT;
	    } else {

	       /* Strip double quotes from string argument */
	       *(arg - 1) = '\0';
	       if (*arg == '"') {
		  arg++;
		  *(arg + (strlen(arg) - 1)) = '\0';
	       }

	       /* Check keyword */
	       if (!Strcmp(keyword, "BEGIN")) {

		  /* Begin new block */
		  status = parse_block(fd, search_keyword(arg,
						 &block_keywords[0]), mode);
	       } else {
		  if (!Strcmp(keyword, "END")) {

		     /* End current block */
		     if (search_keyword(arg, &block_keywords[0]) !=
							       block_type) {
			status = EDITOR_ERROR_END_WRONG_BLOCK;
		     } else {
			status = EDITOR_STATUS_EOB;
		     }
		  } else {

		     /* Parse item */
		     status = parse_item(block_type, keyword, arg, mode);
		  }
	       }
	    }
	 }
      } while (status == EDITOR_STATUS_NORMAL);
      if (status != EDITOR_STATUS_EOB) {
	 if (block_type == BLOCK_TYPE_TEMPLATE && new_template) {
	    free_template(new_template);
	 }
      } else {
	 if (block_type == BLOCK_TYPE_TEMPLATE) {

	    /* Init new template */
	    tp  = new_template;
	    box = &tp->tp_Box;
	    tp->tp_Node.ln_Name = &tp->tp_TemplateName[0];
	    switch (TEMPLATE_GROUP(tp)) {
	       case TEMPLATE_GROUP_BORDER :

		  /* Init border template */
		  bd                = &tp->tp_Data.tp_BorderData;
		  bd->bd_LeftEdge   = box->bo_X1;
		  bd->bd_TopEdge    = box->bo_Y1;
		  bd->bd_Width      = box->bo_X2 - box->bo_X1 + 1;
		  bd->bd_Height     = box->bo_Y2 - box->bo_Y1 + 1;
		  (bd + 1)->bd_Type = INTUISUP_DATA_END;
		  break;

	       case TEMPLATE_GROUP_TEXT :

		  /* Init text template */
		  td                = &tp->tp_Data.tp_TextData;
		  td->td_LeftEdge   = box->bo_X1;
		  td->td_TopEdge    = box->bo_Y1;
		  td->td_TextAttr   = &tp->tp_TextAttr;
		  (td + 1)->td_Type = INTUISUP_DATA_END;
		  break;
	       case TEMPLATE_GROUP_GADGET :

		  /* Init gadget template */
		  gd                = &tp->tp_Data.tp_GadgetData;
		  gd->gd_LeftEdge   = box->bo_X1;
		  gd->gd_TopEdge    = box->bo_Y1;
		  gd->gd_Width      = box->bo_X2 - box->bo_X1 + 1;
		  gd->gd_Height     = box->bo_Y2 - box->bo_Y1 + 1;
		  gd->gd_TextAttr   = &tp->tp_TextAttr;
		  (gd + 1)->gd_Type = INTUISUP_DATA_END;
		  break;
	    }

	    /* Add new template to list and increment counters */
	    tl = &new_template_list;
	    AddTail(&tl->tl_List, &tp->tp_Node);
	    tl->tl_ListEntries++;
	    switch (TEMPLATE_GROUP(tp)) {
	       case TEMPLATE_GROUP_BORDER :
		  tp->tp_GroupEntryNum = ++tl->tl_BorderTemplates;
		  break;

	       case TEMPLATE_GROUP_TEXT :
		  tp->tp_GroupEntryNum = ++tl->tl_TextTemplates;
		  break;

	       case TEMPLATE_GROUP_GADGET :
		  tp->tp_GroupEntryNum = ++tl->tl_GadgetTemplates;
		   break;
	    }
	 }
	 status = EDITOR_STATUS_NORMAL;
      }
   }
   return(status);
}
	/* Parse block of load file */

   STATIC SHORT
parse_item(USHORT block_type, BYTE *keyword, BYTE *arg, USHORT mode)
{
   struct NewWindow     *nwin;
   struct TemplateList  *new_tl;
   struct Template      *tp;
   struct Box           *box;
   struct TextAttr      *ta;
   struct BorderData    *bd;
   struct TextData      *td;
   struct GadgetData    *gd;
   SHORT status = EDITOR_STATUS_NORMAL;

   switch (block_type) {
      case BLOCK_TYPE_HEADER :

	 /* Read header data */
	 if (mode == LOAD_MODE_NORMAL) {
	    nwin   = &project_new_window;
	    new_tl = &new_template_list;
	    switch (search_keyword(keyword, &header_keywords[0])) {
	       case HEADER_ITEM_TYPE_LEFTEDGE :
		  nwin->LeftEdge = Atol(arg);
		  break;

	       case HEADER_ITEM_TYPE_TOPEDGE :
		  nwin->TopEdge = Atol(arg);
		  break;

	       case HEADER_ITEM_TYPE_WIDTH :
		  nwin->Width = Atol(arg);
		  break;

	       case HEADER_ITEM_TYPE_HEIGHT :
		  nwin->Height = Atol(arg);
		  break;

	       case HEADER_ITEM_TYPE_FLAGS :
		  new_tl->tl_Flags = Atol(arg);
		  break;
	    }
	 }
	 break;

      case BLOCK_TYPE_TEMPLATE :

	 /* Read template data */
	 tp = new_template;
	 switch (search_keyword(keyword, &template_keywords[0])) {
	    case TEMPLATE_ITEM_TYPE_NAME :
	       strcpy(&tp->tp_TemplateName[0], arg);
	       break;

	    case TEMPLATE_ITEM_TYPE_TYPE :
	       tp->tp_Type = Atol(arg);
	       break;

	    case TEMPLATE_ITEM_TYPE_FLAGS :
	       tp->tp_Flags = Atol(arg);
	       break;
	 }
	 break;

      case BLOCK_TYPE_BOX :
	 
	 /* Read box data */
	 box = &new_template->tp_Box;
	 switch (search_keyword(keyword, &box_keywords[0])) {
	    case BOX_ITEM_TYPE_X1 :
	       box->bo_X1 = Atol(arg);
	       break;

	    case BOX_ITEM_TYPE_Y1 :
	       box->bo_Y1 = Atol(arg);
	       break;

	    case BOX_ITEM_TYPE_X2 :
	       box->bo_X2 = Atol(arg);
	       break;

	    case BOX_ITEM_TYPE_Y2 :
	       box->bo_Y2 = Atol(arg);
	       break;
	 }
	 break;

      case BLOCK_TYPE_TEXTATTR :
	 
	 /* Read text attribute data */
	 ta = &new_template->tp_TextAttr;
	 switch (search_keyword(keyword, &textattr_keywords[0])) {
	    case TEXTATTR_ITEM_TYPE_NAME :
	       status = duplicate_string((BYTE **)&ta->ta_Name, arg);
	       break;

	    case TEXTATTR_ITEM_TYPE_YSIZE :
	       ta->ta_YSize = Atol(arg);
	       break;

	    case TEXTATTR_ITEM_TYPE_STYLE :
	       ta->ta_Style = Atol(arg);
	       break;

	    case TEXTATTR_ITEM_TYPE_FLAGS :
	       ta->ta_Flags = Atol(arg);
	       break;
	 }
	 break;

      case BLOCK_TYPE_TEXTLIST :

	 /* Read text list */
	 switch (search_keyword(keyword, &textlist_keywords[0])) {
	    case TEXTLIST_ITEM_TYPE_TEXT :
	       status = add_template_text_list_entry(new_template, arg);
	       break;
	 }
	 break;

      case BLOCK_TYPE_BORDERDATA :

	 /* Read border data */
	 bd = &new_template->tp_Data.tp_BorderData;
	 switch (search_keyword(keyword, &borderdata_keywords[0])) {
	    case BORDERDATA_ITEM_TYPE_TYPE :
	       bd->bd_Type = Atol(arg);
	       break;
	 }
	 break;

      case BLOCK_TYPE_TEXTDATA :

	 /* Read text data */
	 td = &new_template->tp_Data.tp_TextData;
	 switch (search_keyword(keyword, &textdata_keywords[0])) {
	    case TEXTDATA_ITEM_TYPE_TYPE :
	       td->td_Type = Atol(arg);
	       break;

	    case TEXTDATA_ITEM_TYPE_FLAGS :
	       td->td_Flags = Atol(arg);
	       break;

	    case TEXTDATA_ITEM_TYPE_TEXT :
	       if (td->td_Type == TEXT_DATA_TYPE_TEXT) {
		  status = duplicate_string(&td->td_Text, arg);
	       } else {
		  td->td_Text = (BYTE *)Atol(arg);
	       }
	       break;
	 }
	 break;

      case BLOCK_TYPE_GADGETDATA :

	 /* Read gadget data */
	 tp = new_template;
	 gd = &tp->tp_Data.tp_GadgetData;
	 switch (search_keyword(keyword, &gadgetdata_keywords[0])) {
	    case GADGETDATA_ITEM_TYPE_TYPE :
	       gd->gd_Type = Atol(arg);
	       break;

	    case GADGETDATA_ITEM_TYPE_FLAGS :
	       gd->gd_Flags = Atol(arg);
	       break;

	    case GADGETDATA_ITEM_TYPE_TEXT :
	       if (*arg == '0') {
		  gd->gd_Text = NULL;
	       } else {
		  status = duplicate_string(&gd->gd_Text, arg);
	       }
	       break;

	    case GADGETDATA_ITEM_TYPE_SPECIAL1 :
	       gd->gd_SpecialData.gd_Data.gd_Data1 = Atol(arg);
	       break;

	    case GADGETDATA_ITEM_TYPE_SPECIAL2 :
	       gd->gd_SpecialData.gd_Data.gd_Data2 = Atol(arg);
	       break;

	    case GADGETDATA_ITEM_TYPE_SPECIAL3 :
	       switch (gd->gd_Type) {
		  case GADGET_DATA_TYPE_BUTTON :
		  case GADGET_DATA_TYPE_CHECK :
		  case GADGET_DATA_TYPE_INTEGER :
		  case GADGET_DATA_TYPE_SLIDER :
		  case GADGET_DATA_TYPE_SCROLLER :
		  case GADGET_DATA_TYPE_COUNT :
		  case GADGET_DATA_TYPE_PALETTE :
		     gd->gd_SpecialData.gd_Data.gd_Data3 = (VOID *)Atol(arg);
		     break;
		  case GADGET_DATA_TYPE_STRING :
		     status = duplicate_string((BYTE **)
				 &gd->gd_SpecialData.gd_Data.gd_Data3, arg);
		     break;
		  case GADGET_DATA_TYPE_MX :
		  case GADGET_DATA_TYPE_CYCLE :
		     status = build_template_text_array(tp);
		     break;
		  case GADGET_DATA_TYPE_LISTVIEW :
		     gd->gd_SpecialData.gd_ListViewData.gd_ListViewList = &tp->tp_TextList;
		     break;
	       }
	       break;
	 }
	 break;
   }
   return(status);
}
	/* Search keyword in given list */

   STATIC USHORT
search_keyword(BYTE *keyword, BYTE **keyword_list)
{
   BYTE   *word;
   USHORT count = 0, num = 0;

   while (word = *keyword_list++) {
      count++;
      if (!Strcmp(word, keyword)) {
	 num = count;
	 break;
      }
   }
   return(num);
}
	/* Open load file */

   STATIC struct FileData *
open_file(BYTE *name)
{
   struct FileData  *fd;

   if (fd = AllocMem((LONG)(sizeof(struct FileData) + MAX_READ_BUFFER_SIZE +
				    MAX_LINE_LEN + 1), (LONG)MEMF_PUBLIC)) {
      if (!(fd->fd_Handle = Open(name, (LONG)MODE_OLDFILE))) {
	 FreeMem(fd, (LONG)(sizeof(struct FileData) + MAX_READ_BUFFER_SIZE +
							 MAX_LINE_LEN + 1));
	 fd = NULL;
      } else {

	 /* Init file data struct */
	 fd->fd_ReadBuffer  = (BYTE *)(fd + 1);
	 fd->fd_CurrentPtr  = NULL;
	 fd->fd_LineBuffer  = fd->fd_ReadBuffer + MAX_READ_BUFFER_SIZE;
	 fd->fd_CurrentLine = 1;
	 fd->fd_Status      = EDITOR_STATUS_NORMAL;
      }
   }
   return(fd);
}
	/* Read line from load file */

   STATIC SHORT
read_line(struct FileData  *fd)
{
   BYTE c, *ptr, *line;
   LONG len;

   /* Fill read buffer */
   if (!(ptr = fd->fd_CurrentPtr) || ptr == fd->fd_EndPtr) {
      ptr = fill_read_buffer(fd);
   }
   if (ptr) {

      /* Find start of line */
      while ((c = *ptr) == ' ' || c == '\t' || c == '\n') {
	 if (c == '\n') {
	    fd->fd_CurrentLine++;
	 }
	 if (++ptr == fd->fd_EndPtr) {
	    if (!(ptr = fill_read_buffer(fd))) {
	       break;
	    }
	 }
      }
   }
   if (ptr) {

      /* Copy line from read buffer to line buffer */
      line = fd->fd_LineBuffer;
      len  = 0;
      while ((c = *ptr) != '\n' && c != '\0') {
	 if (len >= MAX_LINE_LEN) {
	    fd->fd_Status = EDITOR_ERROR_LINE_TOO_LONG;
	    ptr           = NULL;
	    break;
	 } else {
	    *line++ = c;
	    len++;
	    if (++ptr == fd->fd_EndPtr) {
	       if (!(ptr = fill_read_buffer(fd))) {
		  break;
	       }
	    }
	 }
      }
      if (ptr) {

	 /* Mark end of string */
	 *line++           = '\0';
	 fd->fd_CurrentPtr = ptr;
      }
   }
   return(fd->fd_Status);
}
	/* Fill read buffer from load file */

   STATIC BYTE *
fill_read_buffer(struct FileData  *fd)
{
   BYTE  *ptr = NULL;
   LONG  len;
   SHORT status;

   if ((len = Read(fd->fd_Handle, fd->fd_ReadBuffer, (LONG)
					    MAX_READ_BUFFER_SIZE)) == -1L) {
      status = EDITOR_ERROR_READ_FAILED;
   } else {
      if (!len) {
	 status = EDITOR_STATUS_EOF;
      } else {
	 fd->fd_CurrentPtr = ptr = fd->fd_ReadBuffer;
	 fd->fd_EndPtr     = ptr + len;
	 status            = EDITOR_STATUS_NORMAL;
      }
   }
   fd->fd_Status = status;
   return(ptr);
}
	/* Close load file */

   STATIC VOID
close_file(struct FileData  *fd)
{
   Close(fd->fd_Handle);
   FreeMem(fd, (LONG)(sizeof(struct FileData) + MAX_READ_BUFFER_SIZE +
							 MAX_LINE_LEN + 1));
}
