#include "Struct-Saver.h"

/********** externals **********/

extern struct config config;
extern FILE *fhd;

/********** Variablen, Daten, etc. **********/

char *null_str = "NULL";
char buf_str[256], name_str[50], line_str[1024];

int menuitem_cnt = 0, subitem_cnt = 0;

struct str_node *first_str = NULL;

static struct list textattr_list = {NULL, "font", "struct TextAttr", "", 0};
static struct list intuitext_list = {NULL, "text", "struct IntuiText", "", 0};
static struct list border_data_list = {NULL, "border_data", "WORD", "[]", 0};
static struct list border_list = {NULL, "border", "struct Border", "", 0};
static struct list image_data_list = {NULL, "image_data", "UWORD", "[]", 0};
static struct list image_list = {NULL, "image", "struct Image", "", 0};
static struct list menuitem_list = {NULL, NULL, "struct MenuItem", "", 0};
static struct list menu_list = {NULL, "menu", "struct Menu", "", 0};
static struct list gad_boolinfo_list = {NULL, "boolinfo", "struct BoolInfo", "", 0};
static struct list gad_propinfo_list = {NULL, "propinfo", "struct PropInfo", "", 0};
static struct list gad_si_buffer_list = {NULL, "string", "UBYTE", "[]", 0};
static struct list gad_stringinfo_list = {NULL, "stringinfo", "struct StringInfo", "", 0};
static struct list gadget_list = {NULL, "gadget", "struct Gadget", "", 0};

static struct def_struct ta_flags_defs[] =
{  {0x01, "FPF_ROMFONT"}, {0x02, "FPF_DISKFONT"}, {0x04, "FPF_REVPATH"},
   {0x08, "FPF_TALLDOT"}, {0x10, "FPF_WIDEDOT"}, {0x20, "FPF_PROPORTIONAL"},
   {0x40, "FPF_DESIGNED"}, {~0, NULL}
};
static struct def_struct ta_style_defs[] =
{  {0, "FS_NORMAL"}, {0x01, "FSF_UNDERLINED"}, {0x02, "FSF_BOLD"},
   {0x04, "FSF_ITALIC"}, {0x08, "FSF_EXTENDED"}, {~0, NULL}
};
static struct def_struct drawmode_defs[] =
{  {0xf001, "JAM1"}, {1, "JAM2"}, {2, "COMPLEMENT"}, {4, "INVERSVID"},
   {~0, NULL}
};
static struct def_struct mi_flags_defs[] =
{  {0x0001, "CHECKIT"}, {0x0002, "ITEMTEXT"}, {0x0004, "COMMSEQ"},
   {0x0008, "MENUTOGGLE"}, {0x0010, "ITEMENABLED"}, {0x00C0, "HIGHNONE"},
   {0x0040, "HIGHCOMP"}, {0x0080, "HIGHBOX"}, {0x0100, "CHECKED"}, {~0, NULL}
};
static struct def_struct m_flags_defs[] =
{  {0x0001, "MENUENABLED"}, {~0, NULL}
};
static struct def_struct gad_bi_flags_defs[] =
{  {0x0001, "BOOLMASK"}, {~0, NULL}
};
static struct def_struct gad_pi_flags_defs[] =
{  {0x0001, "AUTOKNOB"}, {0x0002, "FREEHORIZ"}, {0x0004, "FREEVERT"},
   {0x0008, "PROPBORDERLESS"}, {0x0010, "PROPNEWLOOK"}, {~0, NULL}
};
static struct def_struct gad_flags_defs[] =
{  {0xf003, "GADGHCOMP"}, {0x0003, "GADGHNONE"}, {0x0001, "GADGHBOX"},
   {0x0002, "GADGHIMAGE"}, {0x0004, "GADGIMAGE"}, {0x0008, "GRELBOTTOM"},
   {0x0010, "GRELRIGHT"}, {0x0020, "GRELWIDTH"}, {0x0040, "GRELHEIGHT"},
   {0x0080, "SELECTED"}, {0x0100, "GADGDISABLED"}, {~0, NULL}
};
static struct def_struct gad_activation_defs[] =
{  {0x0001, "RELVERIFY"}, {0x0002, "GADGIMMEDIATE"}, {0x0004, "ENDGADGET"},
   {0x0008, "FOLLOWMOUSE"}, {0x0010, "RIGHTBORDER"}, {0x0020, "LEFTBORDER"},
   {0x0040, "TOPBORDER"}, {0x0080, "BOTTOMBORDER"}, {0x0100, "TOGGLESELECT"},
   {0x0200, "STRINGCENTER"}, {0x0400, "STRINGRIGHT"}, {0x0800, "LONGINT"},
   {0x1000, "ALTKEYMAP"}, {0x2000, "BOOLEXTEND"}, {~0, NULL}
};
static struct def_struct gad_gadgettype_defs[] =
{  {0x0003, "PROPGADGET"}, {0x0001, "BOOLGADGET"}, {0x0004, "STRGADGET"},
   {0x1000, "REQGADGET"}, {0x2000, "GZZGADGET"}, {0x8000, "SYSGADGET"},
   {~0, NULL}
};

/********** Routinen **********/

STRPTR copy_str(char *s)
/* return ptr to copy of s */
{
   struct str_node *n;

   if (n = malloc(sizeof(struct str_node) + strlen(s)))
   {
      n->next = first_str;
      first_str = n;
      strcpy(n->str, s);
      return(n->str);
   }
   else
   {
      TITLE("Out of memory!");
      return(null_str);
   }
}


void free_strings(void)
/* free all strings */
{
   struct str_node *n = first_str, *next;

   while (n)
   {
      next = n->next;
      free(n);
      n = next;
   }
   first_str = NULL;
}


void free_list(struct list *list)
/* free all nodes of list */
{
   struct node *n = list->head, *next;

   while (n)
   {
      next = n->next;
      free(n);
      n = next;
   }
   list->head = NULL;
   list->cnt = 0;
}


void free_lists(void)
/* free all lists */
{
   free_list(&textattr_list);
   free_list(&intuitext_list);
   free_list(&border_data_list);
   free_list(&border_list);
   free_list(&image_data_list);
   free_list(&image_list);
   free_list(&menuitem_list);
   menuitem_cnt = subitem_cnt = 0;
   free_list(&menu_list);
   free_list(&gad_boolinfo_list);
   free_list(&gad_propinfo_list);
   free_list(&gad_si_buffer_list);
   free_list(&gad_stringinfo_list);
   free_list(&gadget_list);
}


void add_node(struct list *list, APTR ptr)
/* add node to list */
{
   struct node *n;
   char str[20];

   list->cnt++;
   sprintf(str, "%s_%d", list->str, list->cnt);
   sprintf(name_str, "%s %s_%d%s =", list->prefix, list->str, list->cnt, list->suffix);

   if (n = malloc(sizeof(struct node) + strlen(str)))
   {
      n->next = list->head;
      list->head = n;
      n->ptr = ptr;
      strcpy(n->str, str);
   }
   else
      TITLE("Out of memory!");
}


STRPTR find_name(struct list *list, APTR ptr, BOOL aptr_flag)
/* search for ptr in list, found => str, else => null_str */
{
   struct node *n = list->head;

   while (n)
   {
      if (n->ptr == ptr)
	 break;
      n = n->next;
   }
   if (n)
   {
      if (aptr_flag)
	 sprintf(buf_str, "(APTR)(&%s)", n->str);
      else
	 sprintf(buf_str, "&%s", n->str);
      return(copy_str(buf_str));
   }
   else
      return(null_str);
}


BOOL check_exist(struct list *list, APTR ptr)
/* search for ptr in list, found => TRUE, else => FALSE */
{
   struct node *n = list->head;

   while (n)
   {
      if (n->ptr == ptr)
	 return(TRUE);
      n = n->next;
   }
   return(FALSE);
}


void do_define(struct def_struct defs[], UWORD flags, int len)
{
   int i;
   UWORD not_f;
   BOOL first_fl = FALSE, print;
   char str[40];

   if (config.use_defines)
   {
      buf_str[0] = 0;
      if ((flags == 0) && ((defs[0].flag & 0xf000) != 0xf000))
      {
	 if (defs[0].flag == 0)
	    sprintf(buf_str, defs[0].str);
	 else
	 {
	    if (len == 0)
	       sprintf(buf_str, "NULL");
	    else
	       sprintf(buf_str, "0x%0*x", len, flags);
	 }
      }
      else
      {
	 for (i = 0; defs[i].flag != ~0; i++)
	 {
	    print = FALSE;

	    if ((defs[i].flag & 0xf000) == 0xf000)
	    {
	       if (!((defs[i].flag & 0x0fff) & flags))
	       {
		  not_f = defs[i].flag & 0x0fff;
		  print = TRUE;
	       }
	    }
	    else
	       if ((flags & defs[i].flag) == defs[i].flag)
	       {
		  not_f = ~defs[i].flag;
		  print = TRUE;
	       }

	    if (print)
	    {
	       flags &= not_f;
	       if (first_fl)
		  sprintf(str, " | %s", defs[i].str);
	       else
	       {
		  sprintf(str, "%s", defs[i].str);
		  first_fl = TRUE;
	       }
	       strcat(buf_str, str);
	    } /* if () */
	 } /* for (i) */
      }

      if (buf_str[0] == 0)
	 sprintf(buf_str, "0x%x", flags);
   }
   else
   {
      if (len == 0)
	 sprintf(buf_str, "NULL");
      else
	 sprintf(buf_str, "0x%0*x", len, flags);
   }
}


void save_line(void)
{
   int i, old_i, todo = strlen(line_str);
   char *ptr = line_str;

   fprintf(fhd, name_str);

   if (config.expanded)
   {
      fprintf(fhd, "\n{\n   ");

      i = 0;
      while (i < todo)
      {
	 while ((ptr[i] != '~') && (i < todo))
	    i++;
	 ptr[i] = 0;
	 fprintf(fhd, ptr);
	 if (i < todo)
	    fprintf(fhd, "\n   ");
	 i++;
	 ptr += i;
	 todo -= i;
	 i = 0;
      }

      fprintf(fhd, "\n};\n\n");
   }
   else
   {
      for (i = 0; i < todo; i++)       /* remove tildes */
	 if (ptr[i] == '~')
	    ptr[i] = ' ';

      fprintf(fhd, " {");
      i = MIN(config.line_length - strlen(name_str) - 3, todo);

      while (i < todo)
      {
	 old_i = i;
	 while ((ptr[i] != ',') && (i > 0))  /* find comma */
	    i--;
	 if (i == 0)
	 {
	    i = old_i;
	    while ((ptr[i] != ',') && (i < todo))
	       i++;
	 }
	 ptr[i] = 0;		       /* save up to comma */
	 fprintf(fhd, "%s,\n   ", ptr);

	 i++;			       /* skip comma and */
	 if (ptr[i] == ' ')            /* space */
	    i++;
	 ptr += i;		       /* do it for the rest of the string */
	 todo -= i;
	 i = MIN(config.line_length - 4, todo);
      } /* while () */

      fprintf(fhd, "%s};\n", ptr);
   } /* if (expanded) */

   free_strings();
}

/********** get_ - Routinen **********/

STRPTR get_pointer(APTR p)
{
   if (!p)
      return(null_str);
   else
   {
      sprintf(buf_str, "%08x", (ULONG)p);
      return(copy_str(buf_str));
   }
}

STRPTR get_string(UBYTE *s)
{
   if (s)
   {
      sprintf(buf_str, "\"%s\"", s);
      return(copy_str(buf_str));
   }
   else
      return(null_str);
}

/***** TextAttr *****/

STRPTR get_ta_style(UBYTE s)
{
   do_define(ta_style_defs, (UWORD)s, 2);
   return(copy_str(buf_str));
}

STRPTR get_ta_flags(UBYTE f)
{
   do_define(ta_flags_defs, (UWORD)f, 2);
   return(copy_str(buf_str));
}

/***** DrawMode *****/

STRPTR get_drawmode(UBYTE dm)
{
   do_define(drawmode_defs, (UWORD)dm, 2);
   return(copy_str(buf_str));
}

/***** IntuiText *****/

STRPTR get_it_font(struct TextAttr *ta)
{
   return(find_name(&textattr_list, (APTR)ta, FALSE));
}

STRPTR get_it_next(struct IntuiText *it)
{
   return(find_name(&intuitext_list, (APTR)it, FALSE));
}

/***** Border *****/

STRPTR get_bo_xy(WORD *xy)
{
   return(find_name(&border_data_list, (APTR)xy, FALSE));
}

STRPTR get_bo_next(struct Border *bo)
{
   return(find_name(&border_list, (APTR)bo, FALSE));
}

/***** Image *****/

STRPTR get_im_data(UWORD *data)
{
   return(find_name(&image_data_list, (APTR)data, FALSE));
}

STRPTR get_im_next(struct Image *im)
{
   return(find_name(&image_list, (APTR)im, FALSE));
}

/***** MenuItem *****/

STRPTR get_mi_next(struct MenuItem *mi)
{
   return(find_name(&menuitem_list, (APTR)mi, FALSE));
}

STRPTR get_mi_flags(UWORD f)
{
   do_define(mi_flags_defs, f, 4);
   return(copy_str(buf_str));
}

STRPTR get_mi_itemfill(APTR itf, struct MenuItem *mi)
{
   if (mi->Flags & ITEMTEXT)
      return(find_name(&intuitext_list, (APTR)itf, TRUE));
   else
      return(find_name(&image_list, (APTR)itf, TRUE));
}

STRPTR get_mi_selectfill(APTR sf, struct MenuItem *mi)
{
   if (mi->Flags & ITEMTEXT)
      return(find_name(&intuitext_list, (APTR)sf, TRUE));
   else
      return(find_name(&image_list, (APTR)sf, TRUE));
}

STRPTR get_mi_command(UBYTE c)
{
   if ((c >= ' ') && (c <= '~'))
      sprintf(buf_str, "'%c'", c);
   else
      sprintf(buf_str, "0x%02x", (unsigned int)c);

   return(copy_str(buf_str));
}

STRPTR get_mi_subitem(struct MenuItem *si)
{
   return(find_name(&menuitem_list, (APTR)si, FALSE));
}

STRPTR get_mi_nextselect(UWORD ns)
{
   if (config.use_defines)
      return("MENUNULL");
   else
      return("0xFFFF");
}

/***** Menu *****/

STRPTR get_m_next(struct Menu *m)
{
   return(find_name(&menu_list, (APTR)m, FALSE));
}

STRPTR get_m_flags(UWORD f)
{
   do_define(m_flags_defs, f, 4);
   return(copy_str(buf_str));
}

STRPTR get_m_firstitem(struct MenuItem *mi)
{
   return(find_name(&menuitem_list, (APTR)mi, FALSE));
}

/***** BoolInfo *****/

STRPTR get_gad_bi_flags(UWORD f)
{
   do_define(gad_bi_flags_defs, f, 4);
   return(copy_str(buf_str));
}

/***** PropInfo *****/

STRPTR get_gad_pi_flags(UWORD f)
{
   do_define(gad_pi_flags_defs, f, 4);
   return(copy_str(buf_str));
}

/***** StringInfo *****/

STRPTR get_gad_si_buffer(UBYTE *s)
{
   return(find_name(&gad_si_buffer_list, (APTR)s, FALSE));
}

STRPTR get_gad_si_altkeymap(struct Keymap *km)
{
   /* not implemented yet */
   return(null_str);
}

/***** Gadget *****/

STRPTR get_gad_next(struct Gadget *gad)
{
   return(find_name(&gadget_list, (APTR)gad, FALSE));
}

STRPTR get_gad_flags(UWORD f)
{
   do_define(gad_flags_defs, f, 4);
   return(copy_str(buf_str));
}

STRPTR get_gad_activation(UWORD a)
{
   do_define(gad_activation_defs, a, 4);
   return(copy_str(buf_str));
}

STRPTR get_gad_gadgettype(UWORD t)
{
   do_define(gad_gadgettype_defs, t, 4);
   return(copy_str(buf_str));
}

STRPTR get_gad_gadgetrender(APTR gr, struct Gadget *gad)
{
   if (gad->Flags & GFLG_GADGIMAGE)
      return(find_name(&image_list, (APTR)gr, TRUE));
   else
      return(find_name(&border_list, (APTR)gr, TRUE));
}

STRPTR get_gad_selectrender(APTR sr, struct Gadget *gad)
{
   if (gad->Flags & GFLG_GADGIMAGE)
      return(find_name(&image_list, (APTR)sr, TRUE));
   else
      return(find_name(&border_list, (APTR)sr, TRUE));
}

STRPTR get_gad_text(struct IntuiText *it)
{
   return(find_name(&intuitext_list, (APTR)it, FALSE));
}

STRPTR get_gad_specialinfo(APTR si, struct Gadget *gad)
{
   if (gad->GadgetType & GTYP_BOOLGADGET)
      return(find_name(&gad_boolinfo_list, (APTR)si, TRUE));
   else if (gad->GadgetType & GTYP_PROPGADGET)
      return(find_name(&gad_propinfo_list, (APTR)si, TRUE));
   else if (gad->GadgetType & GTYP_STRGADGET)
      return(find_name(&gad_stringinfo_list, (APTR)si, TRUE));
   else 			    /* other type??? */
      return("unknown");
}

/********** _name - Routinen **********/

void textattr_name(struct TextAttr *ta)
{
   add_node(&textattr_list, (APTR)ta);
}


void intuitext_name(struct IntuiText *it)
{
   add_node(&intuitext_list, (APTR)it);
}


void border_data_name(WORD *bd)
{
   add_node(&border_data_list, (APTR)bd);
   fprintf(fhd, name_str);
}


void border_name(struct Border *bo)
{
   add_node(&border_list, (APTR)bo);
}


void image_data_name(UWORD *id)
{
   add_node(&image_data_list, (APTR)id);
   fprintf(fhd, name_str);
}


void image_name(struct Image *im)
{
   add_node(&image_list, (APTR)im);
}


void menuitem_name(struct MenuItem *mi, BOOL subitem)
{
   if (subitem)
   {
      menuitem_list.str = "subitem";
      menuitem_list.cnt = subitem_cnt;
   }
   else
   {
      menuitem_list.str = "item";
      menuitem_list.cnt = menuitem_cnt;
   }
   add_node(&menuitem_list, (APTR)mi);
   if (subitem)
      subitem_cnt = menuitem_list.cnt;
   else
      menuitem_cnt = menuitem_list.cnt;
}


void menu_name(struct Menu *m)
{
   add_node(&menu_list, (APTR)m);
}


void gad_boolinfo_name(struct BoolInfo *bi)
{
   add_node(&gad_boolinfo_list, (APTR)bi);
}


void gad_propinfo_name(struct PopInfo *pi)
{
   add_node(&gad_propinfo_list, (APTR)pi);
}


void gad_si_buffer_name(UBYTE *buf)
{
   add_node(&gad_si_buffer_list, (APTR)buf);
   fprintf(fhd, name_str);
}


void gad_stringinfo_name(struct StringInfo *si)
{
   add_node(&gad_stringinfo_list, (APTR)si);
}


void gadget_name(struct Gadget *gad)
{
   add_node(&gadget_list, (APTR)gad);
}

/********** save_ - Routinen **********/

/***** Text *****/

void save_textattr(struct TextAttr *ta)
{
   if (!ta || (ULONG)ta & 1) return;            /* security check */
   if (check_exist(&textattr_list, (APTR)ta)) return;

   textattr_name(ta);
   sprintf(line_str, "\"%s\", %d,~%s,~%s",
	 ta->ta_Name, ta->ta_YSize, get_ta_style(ta->ta_Style),
	 get_ta_flags(ta->ta_Flags));
   save_line();
}


void save_intuitext(struct IntuiText *it)
{
   if (!it || (ULONG)it & 1) return;            /* security check */
   if (check_exist(&intuitext_list, (APTR)it)) return;

   if (it->NextText) save_intuitext(it->NextText);
   if (it->ITextFont) save_textattr(it->ITextFont);
   intuitext_name(it);
   sprintf(line_str, "%d,%d, %s, %d,%d,~%s,~%s,~%s",
	 it->FrontPen, it->BackPen, get_drawmode(it->DrawMode),
	 it->LeftEdge, it->TopEdge, get_it_font(it->ITextFont),
	 get_string(it->IText), get_it_next(it->NextText));
   save_line();
}

/***** Border *****/

void save_border_data(WORD *bd, int n)
{
   int i;

   if (!bd || (ULONG)bd & 1) return;            /* security check */
   if (check_exist(&border_data_list, (APTR)bd)) return;

   border_data_name(bd);
   fprintf(fhd, " {");
   for (i = 0; i < n; i++, bd += 2)
   {
      fprintf(fhd, "%d,%d", *bd, *(bd+1));
      if (i < n-1)
	 fprintf(fhd, ", ");
   }
   fprintf(fhd, "};\n");
}


void save_border(struct Border *bo)
{
   if (!bo || (ULONG)bo & 1) return;            /* security check */
   if (check_exist(&border_list, (APTR)bo)) return;

   if (bo->NextBorder) save_border(bo->NextBorder);
   if (bo->XY) save_border_data(bo->XY, (int)bo->Count);
   border_name(bo);
   sprintf(line_str, "%d,%d, %d,%d, %s,~%d, %s,~%s",
	 bo->LeftEdge, bo->TopEdge, bo->FrontPen, bo->BackPen,
	 get_drawmode(bo->DrawMode), bo->Count, get_bo_xy(bo->XY),
	 get_bo_next(bo->NextBorder));
   save_line();
}

/***** Image *****/

void save_image_data(UWORD *id, WORD w, WORD h, WORD d)
{
   int i,j;

if (d > 6) d = 6;

   if (!id || (ULONG)id & 1) return;            /* security check */
   if (check_exist(&image_data_list, (APTR)id)) return;

   image_data_name(id);
   fprintf(fhd, "\n{");
   for (i = 0; i < d; i++)
   {
      for (j = 0; j < (w+15)/16*h; j++, id++)
      {
	 if (j % 8 == 0)                  /* 8 Zahlen pro Zeile */
	    fprintf(fhd, "\n   ");
	 fprintf(fhd, "0x%04x, ", *id);
      }
      fprintf(fhd, "\n");
   } /* for (i) */
   fprintf(fhd, "};\n");
}


void save_image(struct Image *im)
{
   if (!im || (ULONG)im & 1) return;            /* security check */
   if (check_exist(&image_list, (APTR)im)) return;

   if (im->NextImage) save_image(im->NextImage);
   if (im->ImageData) save_image_data(im->ImageData, im->Width, im->Height, im->Depth);
   image_name(im);
   sprintf(line_str, "%d,%d, %d,%d, %d,~%s,~0x%02x, 0x%02x,~%s",
	 im->LeftEdge, im->TopEdge, im->Width, im->Height, im->Depth,
	 get_im_data(im->ImageData), (unsigned int)im->PlanePick,
	 (unsigned int)im->PlaneOnOff, get_im_next(im->NextImage));
   save_line();
}

/***** Menu *****/

void save_menuitem(struct MenuItem *mi, BOOL subitem)
{
   if (!mi || (ULONG)mi & 1) return;            /* security check */

   if (mi->NextItem) save_menuitem(mi->NextItem, subitem);
   if (mi->SubItem) save_menuitem(mi->SubItem, TRUE);
   if (mi->ItemFill)
   {
      if (mi->Flags & ITEMTEXT)
	 save_intuitext((struct IntuiText *)mi->ItemFill);
      else
	 save_image((struct Image *)mi->ItemFill);
   }
   if (mi->SelectFill)
   {
      if (mi->Flags & ITEMTEXT)
	 save_intuitext((struct IntuiText *)mi->ItemFill);
      else
	 save_image((struct Image *)mi->ItemFill);
   }
   menuitem_name(mi, subitem);
   sprintf(line_str, "%s,~%d,%d, %d,%d,~%s,~0x%08x,~%s, %s,~%s, %s, %s",
	 get_mi_next(mi->NextItem), mi->LeftEdge, mi->TopEdge, mi->Width,
	 mi->Height, get_mi_flags(mi->Flags), mi->MutualExclude,
	 get_mi_itemfill(mi->ItemFill, mi),
	 get_mi_selectfill(mi->SelectFill, mi),
	 get_mi_command(mi->Command), get_mi_subitem(mi->SubItem),
	 get_mi_nextselect(mi->NextSelect));
   save_line();
}


void save_menu(struct Menu *m)
{
   if (!m || (ULONG)m & 1) return;              /* security check */

   if (m->NextMenu) save_menu(m->NextMenu);
   if (m->FirstItem) save_menuitem(m->FirstItem, FALSE);
   menu_name(m);
   sprintf(line_str, "%s,~%d,%d, %d,%d,~%s,~%s,~%s, 0,0,0,0",
	 get_m_next(m->NextMenu), m->LeftEdge, m->TopEdge, m->Width,
	 m->Height, get_m_flags(m->Flags), get_string(m->MenuName),
	 get_m_firstitem(m->FirstItem));
   save_line();
}

/***** Gadget *****/

void save_gad_boolinfo(struct BoolInfo *bi, struct Gadget *gad)
{
   if (!bi || (ULONG)bi & 1) return;            /* security check */

   if (bi->Mask) save_image_data(bi->Mask, gad->Width, gad->Height, 1);
   gad_boolinfo_name(bi);
   sprintf(line_str, "%s,~%s, 0",
	 get_gad_bi_flags(bi->Flags), get_im_data(bi->Mask));
   save_line();
}


void save_gad_propinfo(struct PropInfo *pi)
{
   if (!pi || (ULONG)pi & 1) return;            /* security check */

   gad_propinfo_name(pi);
   sprintf(line_str, "%s,~0x%04x,0x%04x, 0x%04x,0x%04x,~0,0,0,0,0,0",
	 get_gad_pi_flags(pi->Flags), pi->HorizPot, pi->VertPot,
	 pi->HorizBody, pi->VertBody);
   save_line();
}


void save_gad_si_buffer(UBYTE *buf)
{
   if (!buf) return;

   gad_si_buffer_name(buf);
   fprintf(fhd, " \"%s\";\n", buf);
}


void save_gad_si_altkeymap(struct KeyMap *keymap)
{
   if (!keymap || (ULONG)keymap & 1) return;
   /* not implemented yet */
}


void save_gad_stringinfo(struct StringInfo *si)
{
   if (!si || (ULONG)si & 1) return;            /* security check */

   if (si->Buffer) save_gad_si_buffer(si->Buffer);
   if (si->UndoBuffer) save_gad_si_buffer(si->UndoBuffer);
   if (si->AltKeyMap) save_gad_si_altkeymap(si->AltKeyMap);
   gad_stringinfo_name(si);
   sprintf(line_str, "%s, %s,~%d, %d, %d,~0,0,0,0,0, NULL, 0, %s",
	 get_gad_si_buffer(si->Buffer),
	 get_gad_si_buffer(si->UndoBuffer), si->BufferPos, si->MaxChars,
	 si->DispPos, get_gad_si_altkeymap(si->AltKeyMap));
   save_line();
}


void save_gadget(struct Gadget *gad)
{
   if (!gad || (ULONG)gad & 1) return;          /* security check */

   if (gad->NextGadget) save_gadget(gad->NextGadget);
   if (gad->GadgetRender)
   {
      if (gad->Flags & GFLG_GADGIMAGE)
	 save_image((struct Image *)gad->GadgetRender);
      else
	 save_border((struct Border *)gad->GadgetRender);
   }
   if (gad->SelectRender)
   {
      if (gad->Flags & GFLG_GADGIMAGE)
	 save_image((struct Image *)gad->SelectRender);
      else
	 save_border((struct Border *)gad->SelectRender);
   }
   if (gad->GadgetText) save_intuitext(gad->GadgetText);
   if (gad->SpecialInfo)
   {
      if (gad->GadgetType & GTYP_BOOLGADGET)
	 save_gad_boolinfo((struct BoolInfo *)gad->SpecialInfo, gad);
      else if (gad->GadgetType & GTYP_PROPGADGET)
	 save_gad_propinfo((struct PropInfo *)gad->SpecialInfo);
      else if (gad->GadgetType & GTYP_STRGADGET)
	 save_gad_stringinfo((struct StringInfo *)gad->SpecialInfo);
   }
   gadget_name(gad);
   sprintf(line_str, "%s,~%d,%d, %d,%d,~%s,~%s,~%s,~%s, %s,~%s,~0x00000000,~%s,~%d, %s",
	 get_gad_next(gad->NextGadget), gad->LeftEdge, gad->TopEdge,
	 gad->Width, gad->Height, get_gad_flags(gad->Flags),
	 get_gad_activation(gad->Activation),
	 get_gad_gadgettype(gad->GadgetType),
	 get_gad_gadgetrender(gad->GadgetRender, gad),
	 get_gad_selectrender(gad->SelectRender, gad),
	 get_gad_text(gad->GadgetText),
	 get_gad_specialinfo(gad->SpecialInfo, gad),
	 gad->GadgetID, get_pointer(gad->UserData));
   save_line();
}

