/* RC.C--
 * Copyright (c) 1995 Hjort Nidudsson
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <io.h>
#include <dos.h>
#include <dir.h>
#include <time.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <conio.h>

#define RCVERSION	0x0202
//#define __EDIT__

char copyright[] =
"RCEDIT v2.02 Copyright (c) 1995-2012 Hjort Nidudsson\n";

char cp_usage[] =
"\n"
"Usage:   RCEDIT [-options] [source]\n\n"

"-a       Source is ASM file\n"
"-b       Source is a binary file\n"
"-c       Source is C/C++ file (default)\n"
"-o       Source is OMF object file\n"
"-oa      Output <name> to ASM source file\n"
"-ob      Output <name> to IDD binary file\n"
"-oc      Output <name> to C source file\n"
"-oo      Output <name> to OMF object file\n"
"-f<name> Output to file <name>\n"
"-d<name> Read IDD_<name> from <source>, or create <name>\n"
"-q       Operate quietly\n"
"-v       Verbose\n"
"-g       Use graphical color\n"
;

char *ftype_txt[] = {
	"No type: assume \"C\" syntax",
	"C/C++ file",
	"ASM file",
	"Binary file",
	"OMF object file"
};

#define MAXOBJECT       64//128
#define MAXWINDOW       (25*80)
#define MAXALLOCSIZE    (16+(MAXWINDOW*2)+(MAXOBJECT*16))
#define MAXNAMELEN      32

#define MAX_X   	79
#define MAX_Y   	24
#define MAX_ROW 	25
#define MAX_COL 	80

#define MAXATTRIB       (8+16+16)

#define NAMEOFFSET      25
#define TOBJ_DELETED    0xFFFF

#define _A_MLINE	0x0001
#define _A_UTIME	0x0002
#define _A_UDATE	0x0004
#define _A_MENUS	0x0008
#define _A_SLINE	0x0010
#define _A_MOUSE	0x0020
#define _A_COLOR	0x0040

#define	NO_SOURCE	0
#define SOURCE_C	1
#define SOURCE_ASM      2
#define SOURCE_IDD      3
#define SOURCE_OBJ      4
#define DEFAULT_SOURCE	1

typedef struct {
	WORD    version;
	WORD    flag;
	COLOR   dlg;
	COLOR   dos;
      } RCFG;

typedef struct {
	WORD    memsize;	/* alloc size */
	FOBJ    dialog;
	FOBJ    object[MAXOBJECT];
	WCHR    wz[MAXWINDOW + 8];
      } CRES;

typedef struct {
	BYTE x;
	BYTE y;
	BYTE at;
	BYTE ch;
     }  MSXY;

typedef struct {
	RECT    rc;
	int     key;
      } stinfo;

extern ROBJ *IDD_RCDesktop;
extern ROBJ *IDD_RCExternEvent;
extern ROBJ *IDD_RCQuickMenu;
extern ROBJ *IDD_RCExit;
extern ROBJ *IDD_RCChild;
extern ROBJ *IDD_RCSave;
extern ROBJ *IDD_RCHelp;
extern ROBJ *IDD_RCDOBJ;
extern ROBJ *IDD_RCBackground;
extern ROBJ *IDD_RCColor;
extern ROBJ *IDD_RCForeground;
extern ROBJ *IDD_RCAddFrame;
extern ROBJ *IDD_RCTOBJ;
extern ROBJ *IDD_RCOpenFile;
extern ROBJ *IDD_RCdl_flag;

DOBJ *DLG_RCEDIT = NULL;

#define O_type(o)	(o->flag & 0x000F)
#define isOpen()	(dialog.flag & _D_DOPEN)
#define isVisible()     (dialog.flag & _D_ONSCR)
#define isDeleted(o)    (o->flag == TOBJ_DELETED)

int option_d = 0;
int option_g = 0;
int option_q = 0;
int option_v = 0;
int option_f = 0;
int option_new = 0;
int option_src = NO_SOURCE;
int option_out = NO_SOURCE;
int fexist_src = 0;
int dlsize_res = 0;

char cp_statusline[] =
"&F&1 Help  &F&2 Save  &F&3 Open  &F&4 Edit  &F&5 Menu  "
"&F&6 DOBJ  &F&7 Color         &E&s&c Exit";

int endmain = 0;

RCFG config = {
	RCVERSION, 0, {
		{ 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70 },
		{ 0x00,0x0D,0x0F,0x09,0x0F,0x07,0x08,0x07,
		  0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F },
		{ 0,1,7,7,4,63,3,7,56,59,0,0,4,3,63,63  }
	},{
		{ 0x00,0x10,0x70,0x70,0x40,0x30,0x30,0x70 },
		{ 0x00,0x0A,0x0F,0x0B,0x0F,0x07,0x08,0x07,
		  0x08,0x0B,0x00,0x00,0x0F,0x0A,0x0F,0x0F },
		{ 0,1,2,3,4,5,20,7,56,57,58,59,60,61,62,63 }
	}
};

CRES Resource;
WCHR winbuf[MAXWINDOW + 80 + 50 + 32];
TOBJ object[MAXOBJECT];
DOBJ dialog = {
	_D_DMOVE|_D_SHADE|_D_RESAT, 0, 0, { 10,7,10,60 }, NULL, object };

int fsaved_src = 0;
char dialogname[128];
//char replacestring[128];
char identifier[128];
char objectname[MAXOBJECT][128];

stinfo st_line[] = {
	{ { 1,24, 7, 1}, F1 },
	{ {10,24, 6, 1}, F2 },
	{ {18,24, 7, 1}, F3 },
	{ {27,24, 7, 1}, F4 },
	{ {36,24,12, 1}, F5 },
	{ {50,24, 9, 1}, F6 },
	{ {62,24, 7, 1}, F7 },
	{ {71,24, 7, 1}, ESC },
};

/* IO */

int error = 0;
int warning = 0;
long lcount = 0;

char warning_txt[] = "*Warning*";
char error_txt	[] = "**Error**";
char fatal_txt	[] = "**Fatal**";
char error_frm	[] = "%s %s(%lu) %s\n";
char ermsg_frm	[] = "%s(%lu)\n\n%s\n";
char output_frm	[] = "%-17s: %s\n";
char error_msg	[] = "Error messages";
char warning_msg[] = "Warning messages";
char lines_msg	[] = "Lines compiled";
char memory_msg	[] = "Resource size";

char cp_head[] =
"%s %s--\n"
"%s Dialog [IDD_%s]\n"
"%s\n"
"%s Change history:\n"
"%s %02d/%02d/%02d - Auto generated Resource file, RCEDIT v2.00\n"
"%s\n\n"
;

char asm_begin  [] = ";******** Resource begin %s *\n";
char asm_fobj   [] = ";\t{ 0x%04X, %3d, %3d, {%2d,%2d,%2d,%2d} },\n";
char asm_data   [] = ";******** Resource data  *******************\n"
		     "%s_RC LABEL WORD\n";
char asm_ifdef  [] = "ifdef _RCEDIT_\n";
char asm_endif  [] = "endif\n\tDW\t";
char asm_bsize  [] = "\n;\t%d byte\n";
char asm_robj   [] = "IDD_%s DD DGROUP:%s_RC\n"
		     "\n\tpublic\tIDD_%s\n\n";
char asm_end    [] = ";******** Resource end   %s *\n";

char cpp_begin  [] = "/******** Resource begin %s *\n";
char cpp_fobj   [] = "\t{ 0x%04X, %3d, %3d, {%2d,%2d,%2d,%2d} },\n";
char cpp_data   [] = "********* Resource data  *******************/\n"
		     "static\tWORD %s_RC[] = {\n";
char cpp_ifdef  [] = "#ifdef _RCEDIT_\n";
char cpp_endif  [] = "#endif\n\t";
char cpp_bsize  [] = "}; //\t%d byte\n";
char cpp_robj   [] = "WORD *\tIDD_%s = %s_RC;\n";
char cpp_end    [] = "/******** Resource end   %s */\n";

char *res_begin = cpp_begin;
char *res_data = cpp_data;
char *res_end = cpp_end;

int line_id = 0;

char lbuf[512];
FILE *fp_src;
FILE *fp_tmp;

char ext_c  [] = ".c";
char ext_asm[] = ".asm";
char ext_idd[] = ".idd";
char ext_obj[] = ".obj";
char ext_tmp[] = ".tmp";
char ext_bak[] = ".bak";
char *default_ext = ext_idd;

char filename_txt[WMAXPATH];
char filename_src[WMAXPATH];
char filename_out[WMAXPATH];
char filename_tmp[WMAXPATH];
char filename_bak[WMAXPATH];

int update_src = 1;

void rc_loadattrib(void);
void rc_initscreen(void);

int exit_result(int result)
{
	char erst[32];
	char warn[32];
	char line[32];
	char meml[32];

	sprintf(erst, "%d", error);
	sprintf(warn, "%d", error);
	sprintf(line, "%lu", lcount);
	sprintf(meml, "%u byte", dlsize_res);
	if (error == 0)
		strcpy(erst, "None");
	if (warning == 0)
		strcpy(warn, "None");
	printf(output_frm, error_msg, erst);
	printf(output_frm, warning_msg, warn);
	printf(output_frm, lines_msg, line);
	printf(output_frm, memory_msg, meml);
	return result;
}

int lwarning(char *msg)
{
	if (!console)
		printf(error_frm, warning_txt, filename_src, lcount, msg);
	else
		ermsg(warning_txt, ermsg_frm, filename_src, lcount, msg);
	warning++;
	return 0;
}

int lerror(char *msg)
{
	if (!console)
		printf(error_frm, error_txt, filename_src, lcount, msg);
	else
		ermsg(error_txt, ermsg_frm, filename_src, lcount, msg);
	error++;
	return 0;
}

int lfatal(char *msg)
{
	if (!console) {
		printf(error_frm, fatal_txt, filename_src, lcount, msg);
	} else {
		ermsg(fatal_txt, ermsg_frm, filename_src, lcount, msg);
	}
	error++;
	return 0;
}

int IOGetFileType(char *name)
{
	char *p;

	p = strrchr(name, '.');
	if (p == NULL)
		return NO_SOURCE;
	if (stricmp(p, ext_c) == 0)
		return SOURCE_C;
	if (stricmp(p, ext_asm) == 0)
		return SOURCE_ASM;
	if (stricmp(p, ext_idd) == 0)
		return SOURCE_IDD;
	if (stricmp(p, ext_obj) == 0)
		return SOURCE_OBJ;
	return -1;
}

int IOInitSourceFile(char *name)
{
	char *p;
	char tmp[WMAXPATH];
	int  src_type;

	fexist_src = 0;
	strcpy(tmp, name);
	if (access(tmp, 0) == 0) {
		fexist_src = 1;
		if (strchr(tmp, '\\'))
			strcpy(filename_src, wlongpath(tmp, NULL));
		else
			strcpy(filename_src, wlongname(tmp, NULL));
	} else {
		strcpy(filename_src, tmp);
	}
	src_type = IOGetFileType(filename_src);
	if (fexist_src == 0 && src_type == 0) {
		if (option_src == 0)
			option_src = DEFAULT_SOURCE;
		p = ext_c;
		if (option_src == SOURCE_IDD)
			p = ext_idd;
		else if (option_src == SOURCE_ASM)
			p = ext_asm;
		else if (option_src == SOURCE_OBJ)
			p = ext_obj;
		strcat(filename_src, p);
		if (access(filename_src, 0) == 0)
			fexist_src = 1;
	}
	src_type = IOGetFileType(filename_src);
	if (option_src == 0) {
		if (src_type > 0) {
			option_src = src_type;
		} else {
			return lfatal("unknown <source> type");
		}
	}
	if (option_src == SOURCE_ASM) {
		res_begin = asm_begin;
		res_data = asm_data;
		res_end = asm_end;
	} else {
		res_begin = cpp_begin;
		res_data = cpp_data;
		res_end = cpp_end;
	}
	if (option_src == SOURCE_OBJ || option_src == SOURCE_IDD)
		update_src = 0;
	return 1;
}

int IOInitFiles(char *name)
{
	char *p,*q;

	if (IOInitSourceFile(name) == 0)
		return 0;

	if (option_f == 0) {
		strcpy(filename_out, filename_src);
		if (option_out == 0) {
			option_out = option_src;
		} else if (option_src != option_out) {
			q = ext_c;
			if (option_out == SOURCE_ASM)
				q = ext_asm;
			else if (option_out == SOURCE_OBJ)
				q = ext_obj;
			else if (option_out == SOURCE_IDD)
				q = ext_idd;
			p = strrchr(filename_out, '.');
			if (p == NULL)
				strcat(filename_out, q);
			else
				strcpy(p, q);
		}
	} else if (option_out == 0) {
		return lfatal("unknown <target> type");
	}

	if (option_src != option_out &&
	    stricmp(filename_out, filename_src) == 0) {
		q = ext_c;
		if (option_out == SOURCE_ASM)
			q = ext_asm;
		else if (option_out == SOURCE_OBJ)
			q = ext_obj;
		else if (option_out == SOURCE_IDD)
			q = ext_idd;
		p = strrchr(filename_out, '.');
		if (p == NULL) {
			strcat(filename_out, q);
		} else {
			strcpy(p, q);
		}
	}

	strcpy(filename_tmp, filename_out);
	strcpy(filename_bak, filename_out);
	strcpy(strrchr(filename_tmp, '.'), ext_tmp);
	strcpy(strrchr(filename_bak, '.'), ext_bak);
	return 1;
}

FILE *IOOpenSource(char *mode)
{
	lcount = 0;
	fp_src = fopen(filename_src, mode);
	if (fp_src == NULL) {
		if (!console)
			printf("%s Command line: Can't open file: %s\n",
				fatal_txt, filename_src);
		else
			eropen(filename_src);
		error++;
	}
	return fp_src;
}

FILE *IOOpenTemp(void)
{
	if (filename_tmp[0] == 0)
		return NULL;
	fp_tmp = fopen(filename_tmp, "w");
	if (fp_tmp == NULL) {
		if (!console)
			printf("%s Can't open file: %s\n",
				fatal_txt, filename_tmp);
		else
			eropen(filename_tmp);
		error++;
	}
	return fp_tmp;
}

int IOCloseFiles(void)
{
	if (fp_tmp)
		fclose(fp_tmp);
	if (fp_src)
		fclose(fp_src);
	fp_src = NULL;
	fp_tmp = NULL;
	return 0;
}

int IORename(void)
{
	IOCloseFiles();
	remove(filename_bak);
	rename(filename_out, filename_bak);
	rename(filename_tmp, filename_out);
	return 1;
}

int IORemoveTemp(void)
{
	IOCloseFiles();
	remove(filename_tmp);
	return 0;
}

int IOGetLine(void)
{
	if (fgets(lbuf, 256, fp_src) == NULL)
		return 0;
	lcount++;
	return 1;
}

int IOPutline(void)
{
	return (fputs(lbuf, fp_tmp) != -1);
}

int IOFindBegin(void)
{
	while (IOGetLine()) {
		if (strnicmp(lbuf, res_begin, NAMEOFFSET) == 0)
			return 1;
	}
	return 0;
}

int IOTestName(char *name)
{
	char *p;
	char namea[MAXNAMELEN];
	char nameb[MAXNAMELEN];

	if (strnicmp(lbuf, res_begin, NAMEOFFSET) != 0)
		return 0;
	if ((p = strchr(lbuf + NAMEOFFSET, ' ')) == NULL)
		return 0;
	*p = 0;
	strcpy(namea, lbuf + NAMEOFFSET);
	*p = ' ';
	strcpy(nameb, name);
	strrev(nameb);
	strrev(namea);
	if (stricmp(nameb, namea) == 0)
		return 1;
	return 0;
}

int IOFindIDD(char *name)
{
	while (IOFindBegin()) {
		if (IOTestName(name))
			return 1;
	}
	return 0;
}

int IOFindData(char *data)
{
	while (IOGetLine()) {
		if (strnicmp(lbuf, data, 32) == 0)
			return IOGetLine();
	}
	return 0;
}

int IOFindEnd(void)
{
	while (IOGetLine()) {
		if (strnicmp(lbuf, res_end, NAMEOFFSET) == 0)
			return 1;
	}
	return 0;
}

/* Decompress Resource */

int event_child(void)
{
	switch (rsmodal(IDD_RCChild)) {
	case 4: return _C_REOPEN; /* Rewrite dialog and continue*/
	case 3: return _C_ESCAPE; /* Close dialog and return 0  */
	case 2: return _C_RETURN; /* Close dialog and return 1  */
	case 1: return _C_NORMAL; /* Continue dialog    	*/
	}
	return 0;
}

int UnzipResource(int count)
{
	int *w;
	int z,q;
	CRES *p;

	if (count < 8 || count == sizeof(CRES) ||
	    Resource.dialog.rc.x > MAX_X ||
	    Resource.dialog.rc.y > MAX_Y ||
	    Resource.dialog.rc.row > MAX_ROW ||
	    Resource.dialog.rc.col > MAX_COL ||
	    Resource.dialog.count > MAXOBJECT) {
		return 0;
	}
	p = &Resource;
	q = 5 + (Resource.dialog.count * 4);
	w = (int *)p + q;
	z = Resource.dialog.rc.row * Resource.dialog.rc.col;
	option_g = 0;
	console &= ~CON_COLOR;
	if (Resource.dialog.flag & _D_RESAT) {
		option_g = 1;
		console |= CON_COLOR;
		rc_loadattrib();
		if (DLG_RCEDIT)
			rc_initscreen();
		z |= 0x8000;
	} else {
		rc_loadattrib();
	}
	wcunzip(&winbuf, w, z);

	/* Copy resource to dialog */
	memcpy(&dialog, &Resource.dialog, 8);
	dialog.flag = (Resource.dialog.flag & _D_RCSAVE);
	dialog.object = object;
	dialog.wp = rcopen(dialog.rc, dialog.flag, 0, NULL, NULL);
	if (dialog.wp == NULL)
		return 0;
	memcpy(dialog.wp, &winbuf, (dialog.rc.row * dialog.rc.col) * 2);
	dialog.flag |= _D_DOPEN;
	wcstrcpy(dialogname, dialog.wp, dialog.rc.col);
	if (dialog.count) {
		for (q = 0; q < dialog.count; q++) {
			memcpy(&object[q], &Resource.object[q], 8);
			wcstrcpy(object[q].data, rcbprc(dialog.wp, object[q].rc, dialog.rc.col), object[q].rc.col);
			if (object[q].flag & _O_CHILD)
				object[q].proc = event_child;
		}
	}
	return 1;
}

/* Read C file */

int c_cwgetline(void)
{
	if (IOGetLine() == 0)
		return 0;
	if (lbuf[0] == '#') {
		if (IOGetLine() == 0)
			return 0;
	}
	strcpy(lbuf, strstart(lbuf));
	strtrim(lbuf);
	return (lbuf[0] >= '0' && lbuf[0] <= '9');
}

int c_getcw(void *wp)
{
	WORD *w = (WORD*)wp;

	if (lbuf[0] < '0' || lbuf[0] > '9') {
		if (c_cwgetline() == 0)
			return 0;
	}
	*w = (WORD)xtol(&lbuf[2]);
	strcpy(lbuf, lbuf + 7);
	return 1;
}

int cpp_read(char *n)
{
	int *w;
	CRES *p;
	int count;

	if (IOOpenSource("rt") == NULL)
		return 0;
	if (!IOFindIDD(n) || !IOFindData(cpp_data)) {
		lerror(n);
		return IORemoveTemp();
	}
	count = 0;
	p = &Resource;
	w = (int *)p;
	while (c_getcw(w++)) {
		if (++count == sizeof(CRES))
			break;
	}
	IOCloseFiles();
	if (UnzipResource(count) == 0)
		return lerror("UnzipResource(<name>)");
	if (dialogname[0] == 0)
		strcpy(dialogname, n);
	strcpy(identifier, n);
	option_new = 0;
	return 1;
}

/* Read ASM file */

int asm_cwgetline(void)
{
	if (IOGetLine() == 0)
		return 0;
	if (!strnicmp(lbuf, "ifdef", 5)) {
		if (IOGetLine() == 0)
			return 0;
	}
	if (!strnicmp(lbuf, "endif", 5)) {
		if (IOGetLine() == 0)
			return 0;
	}
	strcpy(lbuf, strstart(lbuf));
	strtrim(lbuf);
	if (strnicmp(lbuf, "DW\t", 3))
		return 0;
	strcpy(lbuf, lbuf + 3);
	return (lbuf[0] == '0'); /* '0XXXXh,..' */
}

int asm_getcw(void *wp)
{
	char *p;
	WORD *w = (WORD*)wp;

	if (lbuf[0] != '0') {	/* '0----h,..' */
		if (asm_cwgetline() == 0)
			return 0;
	}
	*w = (WORD)xtol(lbuf + 1);
	if ((p = strchr(lbuf, ',')) != NULL) {
		strcpy(lbuf, p + 1); /* '0----h,[..' */
	} else {
		lbuf[0] = 0;
	}
	return 1;
}

int asm_read(char *name)
{
	CRES *p;
	int *w,count;

	if (IOOpenSource("rt") == NULL)
		return 0;
	if (!IOFindIDD(name) || !IOFindData(asm_data)) {
		lerror("Resource not found");
		return IORemoveTemp();
	}
	count = 0;
	p = &Resource;
	w = (int *)p;
	while (asm_getcw(w++)) {
		if (++count == sizeof(CRES))
			break;
	}
	IOCloseFiles();
	if (UnzipResource(count) == 0)
		return lerror("Error reading Resource");
	return 1;
}

/* Read IDD file */

int bin_read(char *name)
{
	int count;
	char *p;

	if (IOOpenSource("rb") == NULL)
		return 0;
	count = osread(fp_src->file, &Resource, sizeof(CRES));
	IOCloseFiles();
	assert(count != 0);
	dialogname[0] = 0;
	if (UnzipResource(count >> 1) == 0)
		return lerror("UnzipResource(<name>)");
	strcpy(identifier, strfn(name));
	if ((p = strrchr(identifier, '.')) != NULL)
		*p = 0;
	if (*dialogname == 0)
		strcpy(dialogname, identifier);
	return 1;
}

/* Read OBJ file */

#define OMF_THEADR	0x80
#define OMF_COMENT	0x88
#define OMF_PUBDEF	0x90
#define OMF_LNAMES	0x96
#define OMF_SEGDEF	0x98
#define OMF_LEDATA	0xA0
#define OMF_FIXUPP	0x9C
#define OMF_MODEND	0x8A

#ifdef __BORLANDC__
 #pragma option -a-
#else
 #pragma pack( 1 )
// #pragma option -zp=1
#endif

typedef struct {
	BYTE	type;
	WORD	length;
	char	data[1024];
	BYTE	cksum;
      } OMFR;

int OMFRead(OMFR *o)
{
	int h,q;

	h = fp_src->file;
	q = osread(h, o, 3);
	return osread(h, &o->data, o->length) + q;
}

#pragma warn -par

int obj_read(/*char *name*/void)
{
	OMFR omf;

	option_src = SOURCE_OBJ;
	if (IOOpenSource("rb") == NULL)
		return 0;
	if (OMFRead(&omf) == 0 || omf.type != OMF_THEADR)
		return IOCloseFiles();
	if (OMFRead(&omf) == 0 || omf.type != OMF_COMENT)
		return IOCloseFiles();
	if (OMFRead(&omf) == 0 || omf.type != OMF_LNAMES)
		return IOCloseFiles();
	if (OMFRead(&omf) == 0 || omf.type != OMF_SEGDEF)
		return IOCloseFiles();
	if (OMFRead(&omf) == 0 || omf.type != OMF_PUBDEF)
		return IOCloseFiles();
	strncpy(identifier, omf.data + 7, omf.data[2] - 4);
	if (OMFRead(&omf) == 0 || omf.type != OMF_COMENT)
		return IOCloseFiles();
	if (OMFRead(&omf) == 0 || omf.type != OMF_LEDATA)
		return IOCloseFiles();
	IOCloseFiles();
	memcpy(&Resource, omf.data + 3, sizeof(OMFR));
	if (UnzipResource(sizeof(OMFR)) == 0)
		return lerror("UnzipResource(<name>)");
	return 1;
}

int IOReadIDD(char *name)
{
	int result;

	if (!console && option_v)
		printf(output_frm, "Reading IDD", name);
	result = 0;
	switch (option_src) {
	case SOURCE_C:
		result = cpp_read(name);
		break;
	case SOURCE_ASM:
		result = asm_read(name);
		break;
	case SOURCE_IDD:
		result = bin_read(name);
		break;
	case SOURCE_OBJ:
		result = obj_read(/*name*/);
	default:
		break;

	}
	if (result) {
		if (dialogname[0] == 0)
			strcpy(dialogname, name);
		if (identifier[0] == 0)
			strcpy(identifier, name);
	} else if (option_v) {
		lwarning("IDD Not found");
	}
	fsaved_src = result;
	return result;
}

/* Write file */

int IOGetName(char *name)
{
	int result;

	assert(option_src != SOURCE_OBJ);
	assert(option_src != SOURCE_IDD);

	result = 0;
	while ( 1 ) {
		if (IOGetLine() == 0)
			break;
		if (IOTestName(name)) {
			result = 1;
			break;
		}
		if (update_src)
			IOPutline();
	}
	return result;
}

int IOGetEnd(void)
{
	assert(option_src != SOURCE_OBJ);
	assert(option_src != SOURCE_IDD);

	if (update_src && IOFindEnd()) {
		do {
			if (IOGetLine() == 0)
				break;
			IOPutline();
		} while ( 1 );
	}
	return IORename();
}

int IOOnCreate(FILE *fp, int type)
{
	char *p;
	char file[WMAXPATH];

	p = filename_out;
	strcpy(file, strfn(p));
	strupr(file);
	if (type == SOURCE_C)
		fprintf(fp, cp_head,
			"/*", file,
			" *", identifier,
			" *",
			" *",
			" *", getmnd(), getday(), getyear() - 2000,
			" */\n\ntypedef unsigned short WORD;");
	else if (type == SOURCE_ASM)
		fprintf(fp, cp_head,
			";", file,
			";", identifier,
			";",
			";",
			";", getmnd(), getday(), getyear() - 2000,
			"\nINCLUDE\tCLIB.INC\n\n_DATA\tSEGMENT");
	return 1;
}

int IOCreateSource(void)
{
	if (IOOpenSource("w+") == NULL)
		return IORemoveTemp();
	IOOnCreate(fp_src, option_src);
	fclose(fp_src);
	return 1;
}

int IOOpenFiles(void)
{
	if (IOOpenTemp() == NULL)
		return 0;
	fp_src = fopen(filename_src, "r");
	if (fp_src == NULL) {
		if (IOCreateSource() == 0)
			return 0;
		if (IOOpenSource("r") == NULL)
			return IORemoveTemp();
	}
	if (access(filename_out, 0) == 0)
		return 2;
	IOOnCreate(fp_tmp, option_out);
	return 1;
}

void tmp_unget(int c)
{
	if (fp_tmp->cnt + c < fp_tmp->bufsize)
		fp_tmp->bp -= c;
	else if (fp_tmp->cnt >= c)
		fp_tmp->cnt -= c;
}

/* Write C file */

void c_printdw(FILE *fp, WCHR w)
{
	fprintf(fp, "0x%04X,", w);
	if (++line_id > 7) {
		line_id = 0;
		fputs("\n\t", fp);
	}
}

void c_print8b(FILE *fp, void *b)
{
	WCHR *p = b;

	c_printdw(fp, p[0]);
	c_printdw(fp, p[1]);
	c_printdw(fp, p[2]);
	c_printdw(fp, p[3]);
}

int c_write(FILE *fp, char *n)
{
	WCHR *w;
	DOBJ *p;
	TOBJ *o;
	int q;
	int flag;
	int count;
	int wc_count;

	p = &dialog;
	flag = p->flag;
	p->flag = _D_MYBUF | (p->flag & _D_RCSAVE);
	w = Resource.wz;
	count = 1 + p->count;
	wc_count = wczip(w, p->wp, p->rc.col * p->rc.row);

	fprintf(fp, cpp_begin, n);
	fprintf(fp, cpp_fobj, p->flag,
		count - 1, p->index, p->rc.x, p->rc.y, p->rc.col, p->rc.row);
	if (count > 1) {
		o = &object[0];
		for (q = 0; q < count - 1; q++, o++) {
			fprintf(fp, "\t{ 0x%04X, %3d, ", o->flag, o->count);
			if (o->ascii == 0)
				fprintf(fp, "  0,");
			else
				fprintf(fp, "'%c',", o->ascii);
			fprintf(fp, " {%2d,%2d,%2d,%2d} },\n",
				o->rc.x, o->rc.y, o->rc.col, o->rc.row);
		}
	}
	fprintf(fp, cpp_data, n);
	if (p->flag & _D_MENUS)
		fputs(cpp_ifdef, fp);
	fprintf(fp, "\t0x%04X, // Alloc size\n\t", dlmemsize(p));
	line_id = 0;
	c_print8b(fp, p);
	if (count > 1) {
		o = &object[0];
		for (q = 0; q < count - 1; q++, o++) {
			c_print8b(fp, o);
		}
	}
	if (p->flag & _D_MENUS) {
		if (line_id == 0)
			tmp_unget(2);
		line_id = 0;
		fputs("\n", fp);
		fputs(cpp_endif, fp);
	}
	for (q = 0; q < wc_count; q++)
		c_printdw(fp, w[q]);
	if (line_id != 0)
		fputs("\n", fp);
	else
		tmp_unget(1);
	dlsize_res = (2 + (count * 8) + (wc_count * 2));
	fprintf(fp, cpp_bsize, dlsize_res);
	fprintf(fp, cpp_robj, n, n);
	p->flag = flag;
	fprintf(fp, cpp_end, n);
	return wc_count;
}

int cpp_save(char *name)
{
	int window;
	int result;

	if (!console && option_v)
		printf(output_frm, "Updating IDD", name);
	option_out = SOURCE_C;
	if ((result = IOOpenFiles()) == 0)
		return 0;
	if (update_src) {
		result = IOGetName(name);
	} else {
		if (result == 2)
			IOOnCreate(fp_tmp, SOURCE_C);
		result = 0;
	}
	window = dlhide(&dialog);
	c_write(fp_tmp, name);
	if (window)
		dlshow(&dialog);
	if (result == 0)
		return IORename();
	return IOGetEnd();
}

/* Write ASM file */

void asm_printdw(WCHR w)
{
	if (line_id != 0) {
		fputs(",", fp_tmp);
	} else {
		fputs("\n\tDW\t", fp_tmp);
	}
	fprintf(fp_tmp, "0%04Xh", w);
	if (++line_id > 7) {
		line_id = 0;
	}
}

void asm_print8b(void *b)
{
	WCHR *p = b;

	asm_printdw(p[0]);
	asm_printdw(p[1]);
	asm_printdw(p[2]);
	asm_printdw(p[3]);
}

int asm_write(char *name)
{
	WCHR *w;
	DOBJ *p;
	TOBJ *o;
	int q;
	int flag;
	int count;
	int wc_count;

	p = &dialog;
	flag = p->flag;
	p->flag = _D_MYBUF | (p->flag & _D_RCSAVE);
	w = Resource.wz;
	count = 1 + p->count;
	wc_count = wczip(w, p->wp, p->rc.col * p->rc.row);

	fprintf(fp_tmp, asm_begin, name);
	fprintf(fp_tmp, asm_fobj, p->flag,
		count - 1, p->index, p->rc.x, p->rc.y, p->rc.col, p->rc.row);
	if (count > 1) {
		o = &object[0];
		for (q = 0; q < count - 1; q++, o++) {
			fprintf(fp_tmp, ";\t{ 0x%04X, %3d, ", o->flag, o->count);
			if (o->ascii == 0)
				fprintf(fp_tmp, "  0,");
			else
				fprintf(fp_tmp, "'%c',", o->ascii);
			fprintf(fp_tmp, " {%2d,%2d,%2d,%2d} },\n",
				o->rc.x, o->rc.y, o->rc.col, o->rc.row);
		}
	}
	fprintf(fp_tmp, asm_data, name);
	if (p->flag & _D_MENUS)
		fputs(asm_ifdef, fp_tmp);
	fprintf(fp_tmp, "\tDW\t0%04Xh\t; Alloc size", dlmemsize(p));
	line_id = 0;
	asm_print8b(p);
	if (count > 1) {
		o = &object[0];
		for (q = 0; q < count - 1; q++, o++)
			asm_print8b(o);
	}
	if (p->flag & _D_MENUS) {
		if (line_id != 0)
			tmp_unget(1);
		else
			tmp_unget(5);
		line_id = 0;
		fputs("\n", fp_tmp);
		fputs(asm_endif, fp_tmp);
	}
	for (q = 0; q < wc_count; q++)
		asm_printdw(w[q]);
/*	if (line_id != 0) {
		tmp_unget(1);
		fputs("\n", fp_tmp);
	} else {
		tmp_unget(4);
	}*/
	dlsize_res = (2 + (count * 8) + (wc_count * 2));
	fprintf(fp_tmp, asm_bsize, dlsize_res);
	fprintf(fp_tmp, asm_robj, name, name, name);
	p->flag = flag;
	fprintf(fp_tmp, asm_end, name);
	return wc_count;
}

int asm_save(char *name)
{
	int x,result,new_file;

	if (!console && option_v)
		printf(output_frm, "Updating IDD", name);
	option_out = SOURCE_ASM;
	result = IOOpenFiles();
	if (result == 0)
		return 0;
	new_file = 0;
	if (update_src) {
		result = IOGetName(name);
	} else {
		if (result == 2) {
			IOOnCreate(fp_tmp, SOURCE_ASM);
			new_file = 1;
		}
		result = 0;
	}
	x = dlhide(&dialog);
	asm_write(name);
	if (new_file == 1)
		fprintf(fp_tmp, "\n\n_DATA\tENDS\n\n\tEND\n");
	if (x != 0)
		dlshow(&dialog);
	if (result == 0)
		return IORename();
	return IOGetEnd();
}

/* Write IDD file */

int bin_save(char *name)
{
	TOBJ *o;
	int df,flag;
	int count,q;
	int wc_count;

	if (!console && option_v)
		printf(output_frm, "Writing IDD", name);
	update_src = 0;
	option_out = SOURCE_IDD;
	if (IOOpenTemp() == NULL)
		return 0;
	flag = dialog.flag;
	if (isVisible())
		dlhide(&dialog);
	df = dialog.flag;
	dialog.flag = _D_MYBUF | (flag & _D_RCSAVE);
	count = 1 + dialog.count;
	wc_count = wczip(Resource.wz, dialog.wp,
		dialog.rc.col * dialog.rc.row);
	Resource.memsize = dlmemsize(&dialog);
	memcpy(&Resource.dialog, &dialog, 8);
	if (count > 1) {
		o = &object[0];
		for (q = 0; q < count - 1; q++, o++)
			memcpy(&Resource.object[q], o, 8);
	}
	dlsize_res = (2 + (count * 8) + (wc_count * 2));
	oswrite(fp_tmp->file, &Resource, 2 + (count * 8));
	oswrite(fp_tmp->file, &Resource.wz, 2 * wc_count);
	if (flag & _D_ONSCR) {
		dialog.flag = df;
		dlshow(&dialog);
	} else {
		dialog.flag = flag;
	}
	name++;
	return IORename();
}

/* Write OBJ file */

static char COMENT[] = "\x88\x1C\x00\x1A\Doszip Resource Edit v2.00";
static char LNAMES[] = "\x96\x0D\x00\x00\x04\DATA\x05\_DATA";

int OMFWrite(OMFR *o)
{
	char *p;
	int x,chksum;

	p = (char *)o;
	chksum = 0;
	for (x = 0; x < o->length + 2; x++)
		chksum += p[x];
	chksum = ~(chksum - 1);
	p[o->length + 2] = chksum;
	oswrite(fp_tmp->file, o, o->length + 3);
	return chksum;
}

int RCCompressDialog(void)
{
	TOBJ *o;
	int flag;
	int count,q;
	int wc_count;

	flag = dialog.flag;
	if (isVisible())
		dlhide(&dialog);
	dialog.flag = _D_MYBUF | (flag & _D_RCSAVE);
	count = 1 + dialog.count;
	wc_count = wczip(&Resource.wz, dialog.wp, dialog.rc.col * dialog.rc.row);
	Resource.memsize = dlmemsize(&dialog);
	memcpy(&Resource.dialog, &dialog, 8);
	if (count > 1) {
		o = &object[0];
		for (q = 0; q < count - 1; q++, o++)
			memcpy(&Resource.object[q], o, 8);
	}
	if (flag & _D_ONSCR)
		dlshow(&dialog);
	dialog.flag = flag;
	return wc_count;
}

int obj_save(char *name)
{
	int q,c;
	int dsize;
	int wsize;
	OMFR omf;

	if (!console && option_v)
		printf(output_frm, "Writing IDD", name);
	update_src = 0;
	option_out = SOURCE_OBJ;
	dsize = (2 + ((1 + dialog.count) * 8));
	wsize = RCCompressDialog() * 2;
	dlsize_res = dsize + wsize;
	if (dlsize_res > 1020)
		return lerror("Resource is to big -- > 1024");
	strcpy(omf.data + 1, strfn(filename_src));
	if (IOOpenTemp() == NULL)
		return 0;
	omf.type = OMF_THEADR;
	omf.length = strlen(omf.data + 1) + 2;
	omf.data[0] = omf.length - 2;
	OMFWrite(&omf);
	memcpy(&omf, COMENT, sizeof(COMENT));
	OMFWrite(&omf);
	memcpy(&omf, LNAMES, sizeof(LNAMES));
	OMFWrite(&omf);
	q = wsize + dsize + 4;
	omf.type    = OMF_SEGDEF;
	omf.length  = 7;
	omf.data[0] = 0x48;
	omf.data[1] = q;
	omf.data[2] = (q >> 8);
	omf.data[3] = 3;
	omf.data[4] = 2;
	omf.data[5] = 1;
	omf.data[6] = 0;
	OMFWrite(&omf);
	omf.type = OMF_PUBDEF;
	omf.data[0] = 0;
	omf.data[1] = 1;
	strcpy(omf.data + 3, "IDD_");
	strcat(omf.data + 3, identifier);
	strupr(omf.data + 3);
	omf.data[2] = strlen(omf.data + 3);
	omf.length = 7 + omf.data[2];
	q -= 4;
	omf.data[omf.length - 4] = q;
	omf.data[omf.length - 3] = (q >> 8);
	omf.data[omf.length - 2] = 0;
	omf.data[omf.length - 1] = 0;
	OMFWrite(&omf);
	omf.type = OMF_COMENT;
	omf.length = 4;
	omf.data[0] = 0x00;
	c = 0xA2;
	omf.data[1] = c;
	omf.data[2] = 0x01;
	OMFWrite(&omf);
	memzero(omf.data, 1024);
	omf.type = OMF_LEDATA;
	omf.length = q + 8;
	omf.data[0] = 1;
	memcpy(omf.data + 3, &Resource, dsize);
	memcpy(omf.data + 3 + dsize, &Resource.wz, wsize);
	OMFWrite(&omf);
	omf.type = OMF_FIXUPP;
	omf.length = 5;
	omf.data[1] = q;
	q >>= 8;
	c = 0xCC | q;
	omf.data[0] = c;
	omf.data[2] = 0x54;
	omf.data[3] = 1;
	omf.data[4] = 0;
	OMFWrite(&omf);
	omf.type = OMF_MODEND;
	omf.length = 2;
	omf.data[0] = 0;
	OMFWrite(&omf);
	return IORename();
}

int IORCSave(void)
{
	int result;

	if (option_out == SOURCE_C)
		result = cpp_save(identifier);
	else if (option_out == SOURCE_ASM)
		result = asm_save(identifier);
	else if (option_out == SOURCE_IDD)
		result = bin_save(identifier);
	else if (option_out == SOURCE_OBJ)
		result = obj_save(identifier);
	else
		result = 0;
	fsaved_src = result;
	return result;
}

/* Edit */

#define STLCOUNT	(sizeof(st_line) / sizeof(stinfo))
#define ALTX    	0x2D00

static WCHR apbuf[80];

void apushstl(char *cp)
{
	wcpushst(apbuf, cp);
}

void apopstl(void)
{
	wcpopst(apbuf);
}

void rc_loadattrib(void)
{
	if (option_g == 0) {
		memcpy(at_background, &config.dos, 40);
		if (console & 0x80)
			resetpal();
	} else {
		memcpy(at_background, &config.dlg, 40);
		loadpal(at_palett);
	}
}

#define wc_puts(p, lsize, at, count, cp) \
	wcputs(p, MKW(at, lsize), count, cp)

void rc_initscreen(void)
{
	int q;

	rc_loadattrib();
	scputa(0, 1, 80*23, at_Desktop);
	scputa(0, 0, 80, at_Menus);
	scputa(0,24, 80, at_Menus);
	wc_puts(getxyp(1, 24), 80, 15, 0, cp_statusline);
	for (q = 0; q < 8; q++) {
		scputa(1 + q, 1, 1, q | (q << 4));
		scputa(1 + q, 22, 1, q | (q << 4));
	}
	for (q = 8; q < 16; q++) {
		scputa(1 + q, 1, 1, q | 0x10);
		scputa(1 + q, 22, 1, q | 0x10);
	}
}

void rcputidd(char *n)
{
	if (dialog.rc.y) {
		scputc(15, 0, 0, 41, ' ');
		if (n == filename_src)
			scpath(17, 0, 39, n);
		else
			scputf(15, 0, 0, 32, ": IDD_%s", n);
	}
}

int rcupdate(void)
{
	static int  _mousex = 0;
	static int  _mousey = 0;
	static int  _ocount = 0;
	static int  _oindex = 0;
	static int  _dsaved = 0;

	if (fsaved_src != _dsaved) {
		_dsaved = rcxyrow(dialog.rc, 2, 23);
		if (_dsaved)
			_dsaved = dlhide(&dialog);
		if (fsaved_src)
			scputc(2, 23, 0, 1, 196);
		else
			scputc(2, 23, 0, 1, '*');
		if (_dsaved)
			dlshow(&dialog);
		_dsaved = fsaved_src;
	}
	if (dialog.rc.y == 0)
		return 0;
	/* [00:00] [00:00] [00:00] */
	if (_oindex != dialog.index) {
		_oindex = dialog.index;
		scputf(58, 0, 0, 0, "%02d", _oindex);
	}
	if (_ocount != dialog.count) {
		_ocount = dialog.count;
		scputf(61, 0, 0, 0, "%02d", _ocount);
	}
	if (_mousex != mousex()) {
		_mousex = mousex();
		scputf(74, 0, 0, 0, "%02d", _mousex);
		if (_mousex > dialog.rc.x
		 && _mousex < dialog.rc.x + dialog.rc.col)
			scputf(66, 0, 0, 0, "%02d", _mousex - dialog.rc.x);
		 else
			scputf(66, 0, 0, 0, "00");
	}
	if (_mousey != mousey()) {
		_mousey = mousey();
		scputf(77, 0, 0, 0, "%02d", _mousey);
		if (_mousey > dialog.rc.y
		 && _mousey < dialog.rc.y + dialog.rc.row)
			scputf(69, 0, 0, 0, "%02d", _mousey - dialog.rc.y);
		 else
			scputf(69, 0, 0, 0, "00");
	}
	return 0;
}

int event_handler(void)
{
	switch (rsmodal(IDD_RCExternEvent)) {
	case 1: return UP;
	case 2: return ESC;
	case 3: return ENTER;
	case 4: return DOWN;
	}
	return 0;
}

enum {  OBJ_PBUTT,
	OBJ_RBUTT,
	OBJ_CHBOX,
	OBJ_XCELL,
	OBJ_TEDIT,
	OBJ_MENUS,
	OBJ_XHTML,
	OBJ_TYPE7,
	OBJ_TYPE8,
	OBJ_TYPE9,
	OBJ_GLCMD,
	OBJ_DHELP,
	OBJ_TYPE11,
	OBJ_TYPE12,
	OBJ_TYPE13,
	OBJ_TYPE14,

	OBJ_FLAGA,
	OBJ_FLAGB,
	OBJ_FLAGC,
	OBJ_FLAGD,
	OBJ_RADIO,
	OBJ_DEXIT,
	OBJ_CURID,
	OBJ_FLAGE,
	OBJ_FLAGF,
	OBJ_EVENT,
	OBJ_CHILD,
	OBJ_STATE,

	OBJ_RCX,
	OBJ_RCY,
	OBJ_RCCOL,
	OBJ_RCROW,

	OBJ_ASCII,
	OBJ_BCOUNT,
	OBJ_INDEX,
	OBJ_NAME,
	OBJ_OK,
	OBJ_COPY,
	OBJ_DELETE,
	OBJ_CANCEL,
	OBJ_OBJCOUNT
};

DOBJ *tobj_dp;

void object_default(int q)
{
	object[q].rc.x   = 4;
	object[q].rc.y   = 2;
	object[q].rc.col = 8;
	object[q].rc.row = 1;
	object[q].count  = 0;
	object[q].ascii  = 0;
	object[q].flag   = 0xFFFF;
	object[q].data   = objectname[q];
	object[q].proc   = event_handler;
	objectname[q][0] = 0;
}

void objxchg(TOBJ *a, TOBJ *b)
{
	void *p = a->data;

	a->data = b->data;
	b->data = p;
	memxchg(a->data, b->data, 128);
	memxchg(a, b, sizeof(TOBJ));
}

int tobj_moveup(void)
{
	int id;

	if ((id = dialog.index) == 0)
		return 0;
	objxchg(&dialog.object[id], &dialog.object[id - 1]);
	dialog.index--;
	return 1;
}

int tobj_movedown(void)
{
	int id;

	if ((id = dialog.index) == dialog.count - 1)
		return 0;
	objxchg(&dialog.object[id], &dialog.object[id + 1]);
	dialog.index++;
	return 1;
}

void init_rectdlg(TOBJ *o, RECT rc)
{
	sprintf(o[0].data, "%d", rc.x);
	sprintf(o[1].data, "%d", rc.y);
	sprintf(o[2].data, "%d", rc.col);
	sprintf(o[3].data, "%d", rc.row);
}

RECT save_rectdlg(TOBJ *o)
{
	RECT rc;
	rc.x   = atoi(o[0].data);
	rc.y   = atoi(o[1].data);
	rc.col = atoi(o[2].data);
	rc.row = atoi(o[3].data);
	return rc;
}

void init_objectdlg(TOBJ *o, TOBJ *src)
{
	int q;
	char *p;

	tosetbitflag(o + 16, 12, _O_FLAGB, src->flag >> 4);
	q = (src->flag & 15);
	o[q].flag |= _O_RADIO;
	q = src->count;
	q <<= 4;
	sprintf(o[OBJ_BCOUNT].data, "%d", q);
	p = o[OBJ_ASCII].data;
	p[0] = src->ascii;
	p[1] = 0;
	init_rectdlg(&o[OBJ_RCX], src->rc);
}

int tdgetrdid(DOBJ *d)
{
	int x,s;
	TOBJ *o = d->object;

	for (x = 0; x < d->count; x++) {
		if ((o[x].flag & 15) == _O_RBUTT)
			break;
	}
	s = x;
	for (; x < d->count; x++) {
		if (o[x].flag & _O_RADIO)
			return x - s;
	}
	return 0;
}

void save_objectdlg(TOBJ *o, TOBJ *src)
{
	int q,x;
	char *p;

	src->flag = (WORD)(togetbitflag(o + 16, 12, _O_FLAGB) << 4);
	src->flag |= tdgetrdid(tobj_dp);
	src->rc = save_rectdlg(&o[OBJ_RCX]);
	p = o[OBJ_ASCII].data;
	src->ascii = *p;
	p = o[OBJ_BCOUNT].data;
	if ((q = atoi(p)) != 0) {
		x = (q & 0x000F);
		q >>= 4;
		if (x != 0)
			q++;
	}
	src->count = q;
}

int update_object(TOBJ *o)
{
	int     at;
	int     att;
	WCHR *  sw;
	char *  cp;
	RECT    rc;

	mousehide();
	rc = o->rc;
	cp = o->data;
	sw = rcsprcrc(dialog.rc, rc);
	at = getxya(dialog.rc.x, dialog.rc.y + 1);
	att = sw->at;
	fsaved_src = 0;
	switch (O_type(o)) {
	case _O_PBUTT:
		wcputw(sw, rc.col, MKW(at, ' '));
		wcputw(sw + rc.col, 1, MKW(at, ' '));
		wcputw(sw + 81, rc.col, MKW(at, ' '));
		wcpbutt(sw, 80, rc.col, cp);
		break;
	case _O_RBUTT:
		wcputw(sw, rc.col, MKW(at, ' '));
		if (cp != NULL)
			wcputs(sw, 0, 0, cp);
		break;
	case _O_CHBOX:
		wcputw(sw, rc.col, MKW(at, ' '));
		if (cp != NULL)
			wcputs(sw, 0, 0, cp);
		break;
	case _O_TEDIT:
		for (at = 0; at < rc.row; at++, sw += 80)
			wcputw(sw, rc.col, MKW(att, tclrascii));
		break;
	case _O_MENUS:
	case _O_XCELL:
		if (cp != NULL && *cp) {
			wcputw(sw, rc.col, MKW(att, ' '));
			wcputs(sw + 1, 0, 0, cp);
		}
		break;
	case _O_XHTML:
		if (cp != NULL && *cp) {
			wcputw(sw, rc.col, MKW(att, ' '));
			wcputs(sw, 0, 0, cp);
		}
		break;
	default:
		fsaved_src = 1;
		break;
	}
	mouseshow();
	return 0;
}

int event_index(void)
{
	int id;

	id = atoi(tobj_dp->object[OBJ_INDEX].data);
	if (id < dialog.index) {
		while (id < dialog.index) {
			if (tobj_moveup() == 0)
				break;
		}
		if (id < dialog.index)
			ermsg("TObject", "Index out of range: %d", id);
	} else if (id > dialog.index) {
		while (id > dialog.index) {
			if (tobj_movedown() == 0)
				break;
		}
		if (id > dialog.index)
			ermsg("TObject", "Index out of range: %d", id);
	}
	sprintf(tobj_dp->object[OBJ_INDEX].data, "%d", dialog.index);
	return _C_REOPEN;
}

int cmddelete(int id)
{
	int a,q;
	RECT rc;
	TOBJ *o;

	o  = object;
	a  = getxya(dialog.rc.x, dialog.rc.y + 1);
	rc = rcaddrc(dialog.rc, o[id].rc);
	for (q = 0; q < rc.row; q++)
		scputc(rc.x, rc.y + q, a, rc.col, ' ');
	if ((o[id].flag & 15) == _O_PBUTT) {
		scputc(rc.x + rc.col, rc.y, 0, 1, ' ');
		scputc(rc.x, rc.y + 1, 0, rc.col + 2, ' ');
	}
	o[id].flag = TOBJ_DELETED;
	for (q = id + 1; q < dialog.count; q++) {
		if (o[q].flag != TOBJ_DELETED)
			objxchg(&o[q - 1], &o[q]);
	}
	if (dialog.count)
		dialog.count--;
	if (dialog.index >= dialog.count)
		dialog.index--;
	fsaved_src = 0;
	return 1;
}

int getobjid(void)
{
	int id;

	if (++dialog.count >= MAXOBJECT) {
		dialog.count--;
		return -1;
	}
	for (id = 0; id < MAXOBJECT; id++) {
		if (object[id].flag == TOBJ_DELETED)
			break;
	}
	if (id >= MAXOBJECT)
		return -1;
	return id;
}

int cmdeditobj(int id)
{
	TOBJ *o;
	TOBJ *q;
	int result;

	if (isOpen() == 0 || (tobj_dp = rsopen(IDD_RCTOBJ)) == NULL)
		return 0;
	dialog.index = id;
	o = tobj_dp->object;
	o[OBJ_INDEX].proc = event_index;
	o[OBJ_PBUTT].data = "TObject";
	q = &object[id];
	strcpy(o[OBJ_NAME].data, object[id].data);
	sprintf(o[OBJ_INDEX].data, "%d", dialog.index);
	init_objectdlg(o, q);
	dlinit(tobj_dp);
	dlshow(tobj_dp);
	result = dlevent(tobj_dp);
	if (result == 0) {
		dlclose(tobj_dp);
		return 0;
	}
	if (result == OBJ_DELETE + 1) {
		dlclose(tobj_dp);
		cmddelete(dialog.index);
		return -1;
	}
	if (result == OBJ_COPY + 1) {
		if ((result = getobjid()) == -1) {
			dlclose(tobj_dp);
			return 0;
		}
		dialog.index = result;
		strcpy(object[result].data, o[OBJ_NAME].data);
		save_objectdlg(o, &object[result]);
		dlclose(tobj_dp);
		update_object(&object[result]);
		return cmdeditobj(result);
	}
	q = &object[dialog.index];
	strcpy(q->data, o[OBJ_NAME].data);
	save_objectdlg(o, q);
	dlclose(tobj_dp);
	update_object(q);
	return 1;
}

enum {  ID_ADDCANCEL,
	ID_ADDPBUTT,
	ID_ADDRBUTT,
	ID_ADDCHBOX,
	ID_ADDTEDIT,
	ID_ADDXCELL,
	ID_ADDMENUS     };

int cmdaddobj(void)
{
	int id;
	int flag;
	int result;

	flag = _O_PBUTT;
	if ((id = getobjid()) == -1)
		return 0;
	object_default(id);
	object[id].flag = flag;
	result = cmdeditobj(id);
	if (result == 0) {
		object[id].flag = TOBJ_DELETED;
		dialog.count--;
	}
	return result;
}

void dialog_default(void)
{
	int q;

	dialog.flag   = _D_STDDLG;
	dialog.rc.x   = 10;
	dialog.rc.y   = 7;
	dialog.rc.row = 10;
	dialog.rc.col = 60;
	dialog.count  = 0;
	dialog.index  = 0;
	dialog.object = object;
	for (q = 0; q < MAXOBJECT; q++)
		object_default(q);
}

int opendlg(void)
{
	int color;
	RECT rc;

	if (dialog.flag & _D_DOPEN)
		return dlshow(&dialog);
	switch(dialog.flag & 0x7000) {
		case _D_STERR: color = at_Error; break;
		case _D_MENUS: color = at_Menus; break;
		case _D_MUSER: color = at_Desktop; break;
		default:
			color = at_Dialog;
			break;
	}
	if (dialog.flag & _D_MENUS) {
		if ((dialog.wp = (WCHR *)rcopen(
			dialog.rc,
			dialog.flag,
			color,
			NULL,
			dialog.wp)) == NULL) {
			return 0;
		}
		rc = dialog.rc;
		rc.x = 0;
		rc.y = 1;
		rc.row--;
		rcframe(rc, dialog.wp, rc.col, 0x0000);
	} else {
		if ((dialog.wp = (WCHR *)rcopen(
			dialog.rc,
			dialog.flag,
			color,
			dialogname,
			dialog.wp)) == NULL) {
			return 0;
		}
	}
	dialog.flag |= _D_DOPEN;
	dlshow(&dialog);
	return 1;
}

int closedlg(void)
{
	int result;

	result = dlclose(&dialog);
	dialog_default();
	fsaved_src = 0;
	option_new = 1;
	return result;
}

int moveobj(RECT *rp, void *wp, int flag)
{
	int end;
	RECT rc;

	rc = *rp;
	end  = 0;
	while (end == 0) {
		gotoxy(rc.x, rc.y);
		if (mousep() == 1) {
			rc = rcmsmove(rc, wp, flag);
			break;
		} else switch (getkey()) {
		case UP:
			rc = rcmove(rc, wp, flag, rc.x, rc.y - 1);
			break;
		case DOWN:
			rc = rcmove(rc, wp, flag, rc.x, rc.y + 1);
			break;
		case LEFT:
			rc = rcmove(rc, wp, flag, rc.x - 1, rc.y);
			break;
		case RIGHT:
			rc = rcmove(rc, wp, flag, rc.x + 1, rc.y);
			break;
		case ENTER:
			end = 1;
			break;
		case ESC:
			end = ESC;
			break;
		}
	}
	if (end == ESC)
		return 0;
	*rp = rc;
	return 1;
}

/**
 *
 * Get char/attrib/RECT from screen using mouse
 */

char cp_msstart   [] = "Click on start point..";
char cp_msend     [] = "Click on end point..";
char cp_msinvalid [] = "Ivalid point...";

int msinvalid(void)
{
	apushstl(cp_msinvalid);
	while (mousep())
		;
	apopstl();
	return 0;
}

int getxy(int *sx, int *sy, char *msg)
{
	int     x = *sx,
		y = *sy,
		end = 0;

	apushstl(msg);
	while (mousep());

	while (end == 0) {
		gotoxy(x, y);
		switch (getevent()) {
		case UP:
			if (y == 0)
				break;
			y--;
			break;
		case LEFT:
			if (x == 0)
				break;
			x--;
			break;
		case RIGHT: x++; break;
		case DOWN:  y++; break;
		case MOUSECMD:
			x = mousex();
			y = mousey();
		case ENTER:
			end = 1;
			break;
		case ESC:
			end = ESC;
			break;
		}
	}
	*sx = x;
	*sy = y;
	apopstl();
	return (end != ESC);
}

int msgetevent(char *msg)
{
	int event;

	apushstl(msg);
	while (mousep());
	event = getevent();
	apopstl();
	if (event != MOUSECMD)
		return 0;
	return 1;
}

int msgetrc(RECT dl, RECT *rp)
{
	RECT rc;
	int x,y;

	x = dl.x;
	y = dl.y;
	if (getxy(&x, &y, cp_msstart) == 0)
		return 0;
	rc = dl;
	if (rcxyrow(rc, x, y) == 0)
		return msinvalid();
	rc.x = x;
	rc.y = y;
	if (getxy(&x, &y, cp_msend) == 0)
		return msinvalid();
	if (y == rc.y && x == rc.x)
		return msinvalid();
	if (y < rc.y) {
		rc.row = rc.y - y + 1;
		rc.y = y;
	} else {
		rc.row = y - rc.y + 1;
	}
	if (x < rc.x) {
		rc.col = rc.x - x + 1;
		rc.x = x;
	} else {
		rc.col = x - rc.x + 1;
	}
	if (rcinside(dl, rc) != 0)
		return msinvalid();
	*rp = rc;
	return 1;
}

int msget(MSXY *ms, char *cp)
{
	int x,y;

	if (msgetevent(cp) == 0)
		return msinvalid();
	x = mousex();
	y = mousey();
	ms->x = x;
	ms->y = y;
	ms->at = getxya(x, y);
	ms->ch = getxyc(x, y);
	return 1;
}

/**
 *
 * IDD_SaveIDD - Save dialog to file
 */
enum {
	ID_OD,
	ID_OF,
	ID_OC,
	ID_OA,
	ID_OB,
	ID_OO,
	ID_Save,
	ID_Cancel
};

int cmdsave(void)
{
	DOBJ *p;
	int result;

	if (fsaved_src)
		return 0;
	if ((dialog.flag & _D_DOPEN) == 0)
		return 0;
	if ((p = rsopen(IDD_RCSave)) == NULL)
		return 0;

	strcpy(p->object[ID_OD].data, identifier);
	if (option_src == SOURCE_ASM)
		p->object[ID_OA].flag |= _O_RADIO;
	else if (option_src == SOURCE_IDD)
		p->object[ID_OB].flag |= _O_RADIO;
	else if (option_src == SOURCE_OBJ)
		p->object[ID_OO].flag |= _O_RADIO;
	else
		p->object[ID_OC].flag |= _O_RADIO;

	strcpy(p->object[ID_OF].data, filename_out);
	dlinit(p);
	if (dlevent(p) == 0) {
		dlclose(p);
		return 0;
	}

	strcpy(identifier, p->object[ID_OD].data);
	option_out = SOURCE_C;
	if (p->object[ID_OA].flag & _O_RADIO)
		option_out = SOURCE_ASM;
	else if (p->object[ID_OB].flag & _O_RADIO)
		option_out = SOURCE_IDD;
	else if (p->object[ID_OO].flag & _O_RADIO)
		option_out = SOURCE_OBJ;
	option_src = option_out;
	result = IOInitFiles(p->object[ID_OF].data);
	dlclose(p);
	rcputidd(identifier);
	if (result) {
		fsaved_src = IORCSave();
		return fsaved_src;
	}
	return 0;
}

/**
 *
 * IDD_Color - Edit color setup
 */

int child_editattrib(void)
{
	editattrib();
	return _C_NORMAL;
}

int child_editpal(void)
{
	editpal();
	return _C_NORMAL;
}

enum {
	ID_COLOR1,
	ID_COLOR2,
	ID_COLOR3,
	ID_COLOR4,
	ID_COLOR5,
	ID_COLOR6,
	ID_USECOLOR,
	ID_EDITATTRIB,
	ID_EDITPAL,
	ID_STANDARD,
	ID_LOAD,
	ID_SAVE,
	ID_QUIT,
     };

int cmdcolor(void)
{
	DOBJ *d;
	int result;

	if ((d = rsopen(IDD_RCColor)) == NULL)
		return 0;
	dlinit(d);
	d->object[ID_EDITATTRIB].proc = child_editattrib;
	d->object[ID_EDITPAL].proc = child_editpal;
	result = rsevent(IDD_RCColor, d);
	dlclose(d);
	return result;
}

int cmdtext(void)
{
	int  x,y;
	RECT rc;
	WCHR sc[80];
	char cb[80];

	apushstl(cp_msstart);
	while (mousep());
	x = tgetevent();
	apopstl();
	if (x != MOUSECMD)
		return 0;
	rc = dialog.rc;
	x = mousex();
	y = mousey();
	if (rcxyrow(rc, x, y) == 0)
		return 0;
	rc.col -= (x - rc.x);
	rc.x = x;
	rc.y = y;
	rc.row = 1;
	cb[0] = 0;
	rcread(rc, sc);
	if (dledit(cb, rc, 80, 0) != ENTER) {
		rcwrite(rc, sc);
		return 0;
	}
	rcwrite(rc, sc);
	mouseoff();
	wcputs(rcsprc(rc), 80, 0, cb);
	mouseon();
	fsaved_src = 0;
	return 1;
}

int cmdresize(void)
{
	RECT rc;
	WCHR a,b,c,h,v;
	WCHR *wp;
	int ex,x;
	int ey,y;
	int z,q,flag;

	fsaved_src = 0;
	flag = dialog.flag;
	dialog.flag |= _D_CLEAR|_D_FOREG|_D_BACKG;
	while (mousep() == 1) {
		x = mousex();
		y = mousey();
		rc = dialog.rc;
		ex = rc.x + rc.col - 1;
		ey = rc.y + rc.row - 1;
		if (x != ex || y != ey) {
			if (x < rc.x + 10 || y < rc.y + 2) {
				mousewait(x, y, 1);
				continue;
			}
			if (x != ex)
				rc.col = x - rc.x + 1;
			if (y != ey)
				rc.row = y - rc.y + 1;
			wp = (WCHR *)rcopen(rc, dialog.flag & _D_SHADE, 0, 0, 0);
			mousehide();
			z = 0;
			if (x < ex || y < ey) {
				dlhide(&dialog);
				v = dialog.wp[dialog.rc.col];
				a = dialog.wp[dialog.rc.col-1];
				b = dialog.wp[dialog.rc.col*(dialog.rc.row-1)];
				h = dialog.wp[dialog.rc.col*(dialog.rc.row-1)+1];
				c = dialog.wp[dialog.rc.col*(dialog.rc.row-1)+dialog.rc.col-1];
			} else {
				if (x > ex)
					z = x - ex;
				else if (y > ey)
					z = y - ey;
				v = wp[rc.col];
				a = wp[dialog.rc.col-1];
				b = wp[rc.col*(dialog.rc.row-1)];
				h = wp[rc.col*(dialog.rc.row-1)+1];
				c = wp[rc.col*(dialog.rc.row-1)+dialog.rc.col-1];
			}
			dlclose(&dialog);
			wp[rc.col-1] = a;
			wcmemset(&wp[1], wp[1], rc.col-2);
			wp[rc.col*(rc.row-1)] = b;
			wp[rc.col*rc.row-1] = c;
			wcmemset(&wp[(rc.row-1)*rc.col+1], h, rc.col-2);
			b.ch = ' ';
			for (q = 1; q < rc.row-1; q++) {
				wp[rc.col*q] = v;
				wp[rc.col*q+rc.col-1] = v;
				if (z) {
					wcmemset(&wp[rc.col*q+rc.col-1-z], b, z);
				}
			}
			if (y > ey) {
				wcmemset(&wp[rc.col*(rc.row-2)+1], b, rc.col-2);
			}
			wcenter(wp, rc.col, dialogname);
			dialog.rc = rc;
			dialog.wp = wp;
			dialog.flag |= _D_DOPEN;
			mouseshow();
			dlshow(&dialog);
		}
		mousewait(x, y, 1);
	}
	dialog.flag = flag;
	return 0;
}

int cmdmoveobj(int i)
{
	int 	flag;
	int 	result;
	RECT 	rc;
	WCHR *	wp;

	fsaved_src = 0;
	if (dialog.rc.y + dialog.rc.row < 25)
		apushstl("Use Mouse or [Left/Right/Up/Down] to move object..");
	flag = _D_DMOVE|_D_CLEAR|_D_COLOR;
	rc = rcaddrc(dialog.rc, object[i].rc);
	if ((object[i].flag & 15) == _O_PBUTT) {
		rc.row++;
		rc.col++;
	}
	wp = (WCHR *)rcopen(rc, flag, getxya(dialog.rc.x, dialog.rc.y + 1), 0, 0);
	flag |= (_D_DOPEN|_D_ONSCR);
	result = moveobj(&rc, wp, flag);
	if (dialog.rc.y + dialog.rc.row < 25)
		apopstl();
	if (result == 0 ||
	    rc.x < dialog.rc.x ||
	    rc.y < dialog.rc.y ||
	    rc.x + rc.col > dialog.rc.x + dialog.rc.col ||
	    rc.y + rc.row > dialog.rc.y + dialog.rc.row) {
		rcxchg(rc, wp);
		rc.x = object[i].rc.x + dialog.rc.x;
		rc.y = object[i].rc.y + dialog.rc.y;
		rcclose(rc, _D_DOPEN|_D_ONSCR, wp);
		return 0;
	}
	object[i].rc.x = rc.x - dialog.rc.x;
	object[i].rc.y = rc.y - dialog.rc.y;
	rcclose(rc, _D_DOPEN, wp);
	return 1;
}

int cmdmovetext(void)
{
	int 	flag;
	int 	result;
	RECT 	rc;
	void *	wp;

	fsaved_src = 0;
	if (msgetrc(dialog.rc, &rc) == 0)
		return msinvalid();

	flag = _D_DMOVE|_D_CLEAR|_D_COLOR;
	wp = (void *)rcopen(rc, flag, getxya(dialog.rc.x, dialog.rc.y + 1), 0, 0);
	flag |= (_D_DOPEN|_D_ONSCR);
	if (dialog.rc.y + dialog.rc.row < 25)
		apushstl("Mouseclick on first line, or [Left/Right/Up/Down] to move object..");
	while (mousep() == 1);
	result = moveobj(&rc, wp, flag);
	if (dialog.rc.y + dialog.rc.row < 25)
		apopstl();
	rcclose(rc, _D_DOPEN, wp);
	return result;
}

int cmdframe(void)
{
	RECT rc;
	int type;

	if ((type = rsmodal(IDD_RCAddFrame)) == 0)
		return msinvalid();
	if (msgetrc(dialog.rc, &rc) == 0)
		return msinvalid();
	mousehide();
	type--;
	rcframe(rc, getxyp(0, 0), 80, type * 6);
	mouseshow();
	fsaved_src = 0;
	return 1;
}

int cmdclearat(void)
{
	int b,f;

	if (isOpen() == 0)
		return 0;
	if (isVisible() == 0)
		dlshow(&dialog);

	apushstl("Select background color of attrib..");
	if ((b = rsmodal(IDD_RCBackground)) == 0)
		return 0;
	b = (b - 1) << 4;
	apushstl("Select foreground color of attrib..");
	if ((f = rsmodal(IDD_RCForeground)) == 0)
		return 0;
	apopstl();
	b |= (f - 1);
	dlhide(&dialog);
	wcputa(dialog.wp, dialog.rc.col * dialog.rc.row, b);
	dlshow(&dialog);
	fsaved_src = 0;
	return 1;
}

int cmdclearfg(void)
{
	int x,y,a,n;
	MSXY ms;

	if (isOpen() == 0)
		return 0;
	if (isVisible() == 0)
		dlshow(&dialog);
	if (msget(&ms, "Click on foreground color to change..") == 0)
		return 0;
	a = (ms.at & 0x0F);
	if (msget(&ms, "Click to get new foreground color to set..") == 0)
		return 0;
	n = (ms.at & 0x0F);
	dlhide(&dialog);
	for (x = 0; x < dialog.rc.col * dialog.rc.row; x++) {
		y = dialog.wp[x].at;
		if ((y & 0x0F) == a) {
			dialog.wp[x].at &= 0xF0;
			dialog.wp[x].at |= n;
		}
	}
	dlshow(&dialog);
	fsaved_src = 0;
	return 1;
}

int cmdfground(void)
{
	int x,y;
	int color;
	RECT rc;

	x = rsmodal(IDD_RCForeground);
	if (x == 0)
		return 0;
	rc = dialog.rc;
	color = x - 1;
	if (rc.y + rc.row < 25)
		apushstl("Click to set foreground..");
	while (mousep());
	while ( 1 ) {
		if (tgetevent() != MOUSECMD)
			break;
		x = mousex();
		y = mousey();
		if (mousep() == 1 && rcxyrow(rc, x, y)) {
			scputfg(x, y, 1, color);
		} else if (mousep() == 2) {
			color = getxya(x, y);
		}
		mousewait(x, y, 1);
	}
	if (rc.y + rc.row < 25)
		apopstl();
	fsaved_src = 0;
	return 1;
}

int cmdclearbg(void)
{
	int x,a,n;
	MSXY ms;

	if (isOpen() == 0)
		return 0;
	if (isVisible() == 0)
		dlshow(&dialog);
	if (msget(&ms, "Click on color to change..") == 0)
		return 0;
	if (rcxyrow(dialog.rc, ms.x, ms.y) == 0)
		return 0;
	a = (ms.at & 0xF0);
	if (msget(&ms, "Click to get new color to set..") == 0)
		return 0;
	n = (ms.at & 0xF0);
	dlhide(&dialog);
	for (x = 0; x < dialog.rc.col * dialog.rc.row; x++) {
		if ((dialog.wp[x].at & 0xF0) == a) {
			dialog.wp[x].at &= 0x0F;
			dialog.wp[x].at |= n;
		}
	}
	dlshow(&dialog);
	fsaved_src = 0;
	return 1;
}

int cmdbground(void)
{
	int x,y;
	int color;
	RECT rc;

	x = rsmodal(IDD_RCBackground);
	if (x == 0)
		return 0;
	rc = dialog.rc;
	color = (x - 1) << 4;
	if (rc.y + rc.row < 25)
		apushstl("Left-Click to set/Right-Click to get background..");
	while ( 1 ) {
		if (tgetevent() != MOUSECMD)
			break;
		x = mousex();
		y = mousey();
		if (mousep() == 1 && rcxyrow(rc, x, y)) {
			scputbg(x, y, 1, color);
		} else if (mousep() == 2) {
			color = getxya(x, y);
		}
		mousewait(x, y, 1);
	}
	if (rc.y + rc.row < 25)
		apopstl();
	fsaved_src = 0;
	return 1;
}

int cmdascii(void)
{
	int ch;
	int q;
	int x,y;
	RECT rc;

	apushstl("Left-Click to set/Right-Click to get ascii..");
	while (mousep());
	q = tgetevent();
	if (q != MOUSECMD) {
		apopstl();
		return 0;
	}
	x = mousex();
	y = mousey();
	ch = getxyc(x, y);
	rc = dialog.rc;
	if (rc.y + rc.row > 23)
		apopstl();
	while ( 1 ) {
		if (tgetevent() != MOUSECMD)
			break;
		x = mousex();
		y = mousey();
		if (mousep() == 1 && rcxyrow(rc, x, y)) {
			scputc(x, y, 0, 1, ch);
		} else if (mousep() == 2) {
			ch = getxyc(x, y);
		}
		mousewait(x, y, 1);
	}
	if (rc.y + rc.row < 24)
		apopstl();
	fsaved_src = 0;
	return 1;
}

int cmdcenter(void)
{
	int x = 40 - (dialog.rc.col / 2);
	int y = 12 - (dialog.rc.row / 2);

	dlhide(&dialog);
	dialog.rc.x = x;
	dialog.rc.y = y;
	dlshow(&dialog);
	fsaved_src = 0;

	return 1;
}

int cmdtitle(void)
{
	int result;

	if ((result = tgetline("Dialogname title", dialogname, 32, 128)) != 0) {
		if (dialog.flag & _D_DOPEN) {
			RECT rc = dialog.rc;
			result = dlhide(&dialog);
			if (dialog.wp[0].ch == ' ')
				wctitle(dialog.wp, rc.col, dialogname);
			else
				wcenter(dialog.wp, rc.col, dialogname);
			if (result)
				dlshow(&dialog);
		}
	}
	return _C_NORMAL;
}

enum {  ID_PBUTT,
	ID_RBUTT,
	ID_CHBOX,
	ID_XCELL,
	ID_TEDIT,
	ID_MENUS,
	ID_XHTML,
	ID_GLCMD,

	ID_RADIO,
	ID_DEXIT,
	ID_FLAGB,
	ID_CURID,
	ID_EXTRN,
	ID_EVENT,
	ID_CHILD,
	ID_STATE,

	ID_NAME,
	ID_BCOUNT,
	ID_ASCII,
	ID_RCX,
	ID_RCY,
	ID_RCCOL,
	ID_RCROW,

	ID_OBJCOUNT
};

enum DObject {
	ID_SETAT = ID_OBJCOUNT,
	ID_SETBG,
	ID_SETFG,
	ID_TITLE,
	ID_OK,
	ID_DCANCEL,
	ID_COUNT,
};

int cmdeditdlg(void)
{
	TOBJ *o;
	DOBJ *d;
	int result;

	if ((d = rsopen(IDD_RCDOBJ)) == NULL)
		return 0;
	o = d->object;
	strcpy(o[ID_NAME].data, identifier);
	tosetbitflag(o, 16, _O_FLAGB, dialog.flag);
	sprintf(o[ID_BCOUNT].data, "%d", dialog.count);
	sprintf(o[ID_ASCII ].data, "%d", dialog.index);
	init_rectdlg(&o[ID_RCX], dialog.rc);
	dlinit(d);
	if ((result = dlevent(d)) == 0) {
		dlclose(d);
		return 0;
	}
	strcpy(identifier, o[ID_NAME].data);
	dialog.flag  = (WORD)togetbitflag(o, 16, _O_FLAGB);
	dialog.rc    = save_rectdlg(&o[ID_RCX]);
	dialog.index = atoi(o[ID_ASCII ].data);
	dlclose(d);
	rcputidd(identifier);
	if (dialog.index >= dialog.count)
		dialog.index = 0;
	switch (result - 1) {
	case ID_SETAT: cmdclearat(); break;
	case ID_SETBG: cmdclearbg(); break;
	case ID_SETFG: cmdclearfg(); break;
	case ID_TITLE: cmdtitle();
	default:
		break;
	}
	fsaved_src = 0;
	return 1;
}

/**
 *
 * Create a new Dialog
 */
int cmdnewdlg(void)
{
	cmdsave();
	closedlg();
	fsaved_src = 0;
	option_new = 1;
	strcpy(identifier, "Dialogname");
	strcpy(dialogname, identifier);
	if (cmdeditdlg() == 0)
		return 0;
	opendlg();
	return 1;
}

int cmdhelp(void)
{
	return rsmodal(IDD_RCHelp);
}

int cmdexit(void)
{
	if (rsmodal(IDD_RCExit))
	       endmain = 1;
	return endmain;
}

int cmdmenu(void)
{
	int x;
	DOBJ *p;

	if ((dialog.flag & _D_ONSCR) == 0)
		return 0;
	if ((p = rsopen(IDD_RCQuickMenu)) == NULL)
		return 0;
	if (mousep() == 2) {
		x = mousex();
		if (x < 60)
			p->rc.x = x;
		else
			p->rc.x = 59;
		p->rc.y = mousey();
	}
	dlshow(p);
	while (mousep());
	switch (dlmodal(p)) {
	case 9: return cmdmovetext();
	case 8: dlinit(&dialog);
		return dlevent(&dialog);
	case 7: return cmdcenter();
	case 6: return cmdbground();
	case 5: return cmdfground();
	case 4: return cmdframe();
	case 3: return cmdascii();
	case 2: return cmdtext();
	case 1: return cmdaddobj();
	default:
		return 0;
	}
}

int mousevent(void)
{
	RECT rc;
	int  x,y,q;

	x = mousex();
	y = mousey();
	if (y == 24) {
		if (isVisible() && dialog.rc.y + dialog.rc.row >= y) {
		} else {
			for (q = 0; q < STLCOUNT; q++) {
				if (rcxyrow(st_line[q].rc, x, y)) {
					mousewait(x, y, 1);
					return st_line[q].key;
				}
			}
			mousewait(x, y, 1);
			return 0;
		}
	}
	if (isVisible() == 0)
		return 0;
	if (rcxyrow(dialog.rc, x, y) == 1) {
		dlmove(&dialog);
		fsaved_src = 0;
		return 0;
	}
	if (y == dialog.rc.y + dialog.rc.row - 1
		&& x == dialog.rc.x + dialog.rc.col - 1) {
		cmdresize();
		return 0;
	}
	for (q = 0; q < dialog.count; q++) {
		rc = rcaddrc(dialog.rc, object[q].rc);
		if (object[q].flag != TOBJ_DELETED) {
			if (rcxyrow(rc, x, y) == 1) {
				if (mousep() == 1)
					cmdmoveobj(q);
				else
					cmdeditobj(q);
				return 1;
			}
		}
	}
	if (mousep() == 2)
		cmdmenu();
	return 0;
}

#define CLEARSTATE      0x03FF

enum {  ID_LISTU,
	ID_LISTD = 11,
	ID_OPEND,
	ID_CANCEL,
	ID_OPENF,
	ID_MOUSEU,
	ID_MOUSED
};

#define OCOUNT  ID_OPEND

LOBJ list;

int open_initlist(void)
{
	int x;

	for (x = 0; x < OCOUNT; x++)
		tdialog->object[x].data = object[list.index + x].data;
	dlinit(tdialog);

	return 1;
}

int open_event_openfile(void)
{
	int x;
	char *p;
	TOBJ *o;

	list.index = 0;
	list.count = 0;
	list.dcount = OCOUNT;
	memset(objectname, 0, sizeof(objectname));
	option_src = 0;
	if (IOInitFiles(filename_src) == 0 || fexist_src == 0)
		return lwarning("File not found");
	if (option_src < SOURCE_IDD) {
		if (IOOpenSource("rt") == NULL)
			return 0;
		while (IOFindBegin()) {
			if ((p = strchr(lbuf + NAMEOFFSET, ' ')) != NULL) {
				*p = 0;
				strcpy(object[list.count++].data, lbuf + NAMEOFFSET);
			}
		}
		IOCloseFiles();
	} else {
		if (identifier[0] == 0) {
			strcpy(identifier, strfn(filename_src));
			if ((p = strrchr(identifier, '.')) != NULL)
				*p = 0;
		}
		strncpy(object[list.count++].data, identifier, 32);
	}
	list.numcel = MIN(list.count, OCOUNT);
	o = tdialog->object;
	for (x = 0; x < list.numcel; x++)
		o[x].flag &= ~_O_STATE;
	for (; x < OCOUNT; x++)
		o[x].flag |= _O_STATE;
	open_initlist();
	dlinit(tdialog);
	if (list.count == 0)
		stdmsg("No object",
			"There is no dialogs saved in\n%s", filename_src);
	return list.count;
}

int ll_eventopen(void)
{
	if (list.celoff >= list.dcount) {
		stdmsg("TDialog", "No item selected\n");
		return _C_NORMAL;
	}
	return _C_RETURN;
}

DOBJ *open_initdlg(void)
{
	TOBJ *o;
	DOBJ *d;

	if ((d = rsopen(IDD_RCOpenFile)) == NULL)
		return NULL;
	list.numcel = 0;
	list.dcount = OCOUNT;
	list.celoff = OCOUNT;
	list.proc   = open_initlist;
	o = d->object;
	o[ID_OPEND].proc  = ll_eventopen;
	o[ID_OPENF].proc  = open_event_openfile;
	o[ID_OPENF].data  = filename_src;
	o[ID_OPENF].count = (WMAXPATH >> 4);
	return d;
}

int cmdopen(void)
{
	DOBJ *d;
	int result;
	char idd[128];

	cmdsave();
	closedlg();
	tclrascii = 250;
	rcputidd(filename_src);
	if ((d = open_initdlg()) == NULL)
		return 0;
	tdialog = d;
	result = open_event_openfile();
	if (result > 1)
		result = dllevent(d, &list);
	else if (result == 1)
		list.celoff = 0;
	dlclose(d);
	if (result == 0 || list.celoff >= OCOUNT)
		return 0;
	strncpy(idd, object[list.index + list.celoff].data, 128);
	dialogname[0] = 0;
	identifier[0] = 0;
	if (IOReadIDD(idd) == 0)
		return 0;
	dlshow(&dialog);
	rcputidd(identifier);
	return 1;
}

#if defined(__EDIT__)

#define	_T_TEDEFAULT	0x1F20

extern int fsflag;
extern int teflag;// = 0x0220;
extern int tepages;// = 128;
extern int telsize;// = 256;
extern char searchstring[128];
extern char configfile[80];

int teoption(void)
{
	strcpy(configfile, _argv[0]);
	strcpy(strfn(configfile), "rc.ini");
	return 0;
}

#if !defined(__WCC__)
int cmdebug(void)
{
	return ermsg(NULL,"hello");
}
#endif

int cmedit(void)
{
	FILE *fp;
	WCHR *wp;
	int x,y,wv,c;

	if (!(dialog.flag & _D_DOPEN))
		return 0;

	teoption();
	strcpy(filename_txt, filename_src);
	setfext(filename_txt, ".txt");
	if ((fp = fopen(filename_txt, "wt+")) == NULL)
		return 0;
	wp = dialog.wp;
	wv = dlhide(&dialog);
	for (y = 0; y < dialog.rc.row; y++) {
		for (x = 0; x < dialog.rc.col; x++) {
			fputc(wp->ch, fp);
			wp++;
		}
		fputc('\n', fp);
	}
	fclose(fp);
	tedit(filename_txt, 0);
/*	if ((fp = fopen(filename_txt, "rt")) == NULL)
		return 0;
	wp = dialog.wp;
	for (y = 0; y < dialog.rc.row; y++) {
		for (x = 0; x < dialog.rc.col; x++) {
			c = fgetc(fp);
			if (c == '\n')
				break;
			wp[x].ch = c;
		}
		wp += dialog.rc.col;
	}
	fclose(fp);
	*/
	if (wv)
		dlshow(&dialog);
	return 1;
}

#endif

int cmuserscreen(void)
{
	mouseoff();
	dlhide(DLG_RCEDIT);
	while (0 == getkey());
	dlshow(DLG_RCEDIT);
	mouseon();
	return 1;
}

int rc_event(int event)
{
	int result;

	switch (event) {
	case F1: return cmdhelp();
	case F2: return cmdsave();
	case F3: return cmdopen();
#if defined(__EDIT__)
	case F4: return cmedit();
#endif
	case F5: return cmdmenu();
	case F6: return cmdeditdlg();
	case F7: return cmdcolor();
	case CTRLF2:
		return cmdnewdlg();
	case CTRLB:
	case ALTF5:
		return cmuserscreen();
	case CTRLF7:
		result = dlhide(&dialog);
		if (console & 0x80) {
			option_g = 0;
			rc_initscreen();
		} else {
			option_g = 1;
			rc_initscreen();
		}
		mouseon();
		if (result)
			dlshow(&dialog);
		return 0;
	case ESC:
		return cmdexit();
	case ALTX:
		endmain = 1;
		return ALTX;
	}
	if (isVisible() == 0)
		return 0;
	if (event == CTRLF8)
		cmdmovetext();
	if (dialog.count == 0)
		return 0;

	switch (event) {
	case UP:
		if (dialog.index)
			dialog.index--;
		else if (dialog.count > 1)
			dialog.index = dialog.count - 1;
		break;
	case TAB:
	case DOWN:
		if (dialog.index == dialog.count - 1)
			dialog.index = 0;
		else if (dialog.count > 1)
			dialog.index++;
		break;
	case ENTER:
		cmdeditobj(dialog.index);
		break;
	case F8:
		cmdmoveobj(dialog.index);
		break;
	case F9:  cmdtext();    break;
	case F10: cmdcenter();  break;
	case F11: cmdfground(); break;
	case F12: cmdbground(); break;
	case CTRLF4:
		cmdascii();
		break;
	case CTRLF5:
		cmdframe();
		break;
	case CTRLF6:
		dlinit(&dialog);
		dlevent(&dialog);
		break;
	}
	return 0;
}

int modal(void)
{
	COBJ cu;
	RECT rc;
	int result;

	cu.flag = 0x0B01;
	while (endmain == 0) {
		if (isVisible() && dialog.count) {
			rc = rcaddrc(dialog.rc, object[dialog.index].rc);
			cu.xpos = rc.x;
			cu.ypos = rc.y;
			setcursor(cu);
		} else {
			cursoroff();
		}
		while (0 == (result = getkey())) {
			tupdate();
			if (mousep()) {
				result = mousevent();
				break;
			}
		}
		if (rc_event(result) == ALTX)
			break;
	}
	closedlg();
	return 0;
}

int rcedit(char *dname)
{
	int result;
	COBJ cursor;

	console |= CON_UTIME;
	if (option_new == 1) {
		if (dname == NULL) {
			if (tgetline("Resource filename", filename_src, 30, 256) == 0)
				return 0;
		} else {
			strcpy(filename_src, dname);
		}
	}
	if (IOInitFiles(filename_src) == 0)
		return 0;

	getcursor(&cursor);
	cursoroff();
	if (option_g) {
		console |= CON_COLOR;
	}
	rc_loadattrib();
	if ((DLG_RCEDIT = rsopen(IDD_RCDesktop)) == NULL)
		return 0;
	dlshow(DLG_RCEDIT);
	mouseinit();
	mouseon();
	rc_initscreen();
	scpath(17, 0, 39, filename_src);
	tupdate = rcupdate;
	if (option_new == 1) {
		cmdnewdlg();
	} else {
		if (isOpen() == 0) {
			if (cmdopen() == 0)
				closedlg();
		} else if (isVisible() == 0) {
			dlshow(&dialog);
		}
	}
	result = modal();
	dlclose(DLG_RCEDIT);
	mouseoff();
	setcursor(cursor);
	resetpal();
	return (result != 0);
}

int main(void)
{
	int result,c;
	char *p;
	char arg_dialog[MAXNAMELEN];

	if (_argc == 1) {
		printf(copyright);
		printf(cp_usage);
		return 1;
	}
	arg_dialog[0] = 0;
	filename_src[0] = 0;
	for (c = 1; c < _argc; c++) {
		switch (_argv[c][0]) {
		case '?':
			printf(copyright);
			printf(cp_usage);
			return 0;
		case '/':
		case '-':
			switch (_argv[c][1] | 0x20) {
			case 'a':
				option_src = SOURCE_ASM;
				break;
			case 'b':
				option_src = SOURCE_IDD;
				update_src = 0;
				break;
			case 'c':
				option_src = SOURCE_C;
				break;
			case 'o':
				result = (_argv[c][2] | 0x20);
				option_out = 0;
				update_src = 0;
				if (result == 'a') {
					option_out = SOURCE_ASM;
				} else if (result == 'b') {
					option_out = SOURCE_IDD;
				} else if (result == 'c') {
					option_out = SOURCE_C;
				} else if (result == 'o') {
					option_out = SOURCE_OBJ;
				} else if (result == 0x20) {
					option_src = SOURCE_OBJ;
				} else if (option_out == 0) {
					lerror(_argv[c]);
					return 1;
				}
				break;
			case 'q':
				option_q = 1;
				break;
			case 'v':
				option_v = 1;
				break;
			case 'd':
				option_d = 1;
				strcpy(arg_dialog, &_argv[c][2]);
				break;
			case 'f':
				option_f = 1;
				strcpy(filename_out, &_argv[c][2]);
				break;
			case 'g':
				option_g = 1;
				break;
			default:
				printf(copyright);
				printf(cp_usage);
				return 0;
			}
			break;
		default:
			strcpy(filename_src, _argv[c]);
			break;
		}
	}
	if (option_q == 0)
		printf("%s\n", copyright);
	if (option_d == 0 && filename_src[0] == 0) {
		lfatal("Command line: missing <source>");
		return exit_result(1);
	}
	dialog_default();
	if (filename_src[0]) {
		if (IOInitSourceFile(filename_src) == 0)
			return exit_result(1);
	} else {
		option_new = 1;
		option_out = option_src;
		return rcedit(arg_dialog);
	}
	if (option_out == 0) {
		option_out = option_src;
		return rcedit(filename_src);
	}

	if (IOInitFiles(filename_src) == 0)
		return exit_result(1);
	if (fexist_src == 0) {
		lfatal("Command line: missing <source>");
		return exit_result(1);
	}
	if (stricmp(strfn(filename_src), strfn(filename_out)) != 0 ||
		option_src == SOURCE_OBJ || option_src == SOURCE_IDD)
		update_src = 0;

	if (option_v) {
		printf(output_frm, "Output file", filename_out);
		printf(output_frm, "Output type", ftype_txt[option_out]);
		printf(output_frm, "Source type", ftype_txt[option_src]);
	}
	if (option_q == 0)
		printf(output_frm, "Assembling file", filename_src);
	if (option_d) {
		strcpy(identifier, arg_dialog);
	} else {
		strncpy(identifier, strfn(filename_src), 128);
		if ((p = strrchr(identifier, '.')) != NULL)
			*p = 0;
	}
	strcpy(arg_dialog, identifier);
	if (IOReadIDD(arg_dialog) == 0)
		return exit_result(1);

	if (IORCSave() == 0)
		return exit_result(1);
	if (option_q == 0)
		return exit_result(0);
	return 0;
}
