pdb.cpp

来自「smallbasic for linux」· C++ 代码 · 共 558 行

CPP
558
字号
/*
*	BAS (text) to PDB
*
*	Nicholas Christopoulos
*/

/*
*	Each DOC is a basic module
*	Each module has 
*		record 0 - type: info_t, the header
*		record 1 - type: sec_t,  the main code section
*		record n - type: sec_t,  code section
*
* 	Each section can be a function or a procedure.
* 	The maximum size of each section is 32KB (FIELD limit).
*/

#define	MAX_SEC		255
#define	MAX_SBTEXT	0x100000

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#if defined(_UnixOS)
	#include <unistd.h>
	#if !defined(O_BINARY)
		#define	O_BINARY	0
	#endif
#else
	#if defined(__GNUC__)
		#include <unistd.h>
	#else
		#include <stdlib.h>
		#include <io.h>
	#endif
#endif
#include <time.h>
#include <sys/stat.h>
//#include "pmem.h"

typedef	unsigned char	byte;
typedef int				int32;
typedef	int short		int16;
typedef	char *			char_p;

void	err_printf(const char *fmt, ...);
void	con_printf(const char *fmt, ...);

#define	DT_UTDIF	12345678

// DATE FIELDs
// expressed as the number of seconds since January 1, 1904.
// The database will not install if this value is zero. (PalmOS 1.0.6) 

int32	PalmNOW()
{
/*	time_t	now;
	
	time(&now);
	now += DT_UTDIF;
	return now;
*/
	return -1;
}

void	write_i16(int handle, int16 x)
{
	byte	y;

	y = x >> 8;
	write(handle, &y, 1); 
	y = x & 0xFF;
	write(handle, &y, 1);
}

void	write_i32(int handle, int32 x)
{
	write_i16(handle, x >> 16);
	write_i16(handle, x & 0xFFFF);
}

void	read_i16(int handle, int16& x)
{
	byte		a, b;
	
	read(handle, &a, 1); 
	read(handle, &b, 1);
	x = (a << 8) | b;
}

void	read_i32(int handle, int32& x)
{
	int16		a, b;
	
	read_i16(handle, a);
	read_i16(handle, b);
	x = (a << 16) | b;
}

void	change_file_ext(char *file, char *ext)
{
	char	*p = strrchr(file, '.');
	char	*e = ext;

	if	( p )
		p ++;
	if	( *e == '.' )
		e ++;

	if	( p )	{
		*p = '\0';
		strcat(file, e);
		}
	else	{
		strcat(file, ".");
		strcat(file, e);
		}
}

/*
*	PDB FILE HEADER
*/
class PDBHeader	{
public:

	char	name[32];
	int16	attr;			// 0x2 RO, 0x4 dirty, 0x8 backup, 0x10 ok to install newer,
							// 0x20 reset after install, 0x40 dont allow copy/beam
	int16	ver;			// app
	int32	dt_created;	
	int32	dt_modified;
	int32	dt_backup;
	int32	mod_num;		// always 0 ?
	int32	app_info_pos;	// 0 = no appinf
	int32	sort_info_pos;	// 0 = no ?
	byte	type[4];
	byte	creator[4];
	byte	uniq[4];		// 0 ??
	int32	next;			// 0
	int16	counter;		// record counter

	PDBHeader();
	void	Write(int handle);
	void	Read(int handle);
	};


PDBHeader::PDBHeader()
{
	memset(name, 0, 32);
	attr = 0;
	ver = 0;
	strncpy((char*)&dt_created, "\x06\xD1\x44\xAE", 4);
	strncpy((char*)&dt_modified, "\x06\xD1\x44\xAE", 4);
	dt_backup = 0;
	mod_num = 0;
	app_info_pos = sort_info_pos = 0;
	memcpy(type, "TEXT", 4);
	memcpy(creator, "SmBa", 4);
	memset(uniq, 0, 4);
	next = 0;
	counter = 0;
}

void	PDBHeader::Write(int handle)
{
	write(handle, &name, 32);
	write_i16(handle, attr);
	write_i16(handle, ver);
	write(handle, &dt_created, 4);	
	write(handle, &dt_modified, 4);
	write_i32(handle, dt_backup);
	write_i32(handle, mod_num);
	write_i32(handle, app_info_pos);
	write_i32(handle, sort_info_pos);
	write(handle, &type, 4);
	write(handle, &creator, 4);
	write(handle, &uniq, 4);
	write_i32(handle, next);
	write_i16(handle, counter);
}

void	PDBHeader::Read(int handle)
{
	read(handle, &name, 32);
	read_i16(handle, attr);
	read_i16(handle, ver);
	read(handle, &dt_created, 4);	
	read(handle, &dt_modified, 4);
	read_i32(handle, dt_backup);
	read_i32(handle, mod_num);
	read_i32(handle, app_info_pos);
	read_i32(handle, sort_info_pos);
	read(handle, &type, 4);
	read(handle, &creator, 4);
	read(handle, &uniq, 4);
	read_i32(handle, next);
	read_i16(handle, counter);
}

/*
*	PDB RECORD HEADER
*/
class PDBRecordHeader	{
public:
	int32	offset;
	int32	index;

	PDBRecordHeader()	{ offset = 0; index = (0x40 << 24) | 0x59A000; }
	void Write(int handle)	{ write_i32(handle, offset); write_i32(handle, index); }
	void Read(int handle)	{ read_i32(handle, offset); read_i32(handle, index); }
	};

/*
*	SmallBASIC - doc section
*/
class SMBasDocSec {
public:
	byte	sign;					// always = 'S'
	byte	unused;					//
	int16	version;				// 
	int16	flags;					// 1 for main section
	char	name[64];

	SMBasDocSec()		{ sign = 'S'; unused = 0; version = 1; flags = 1; strcpy(name, "Main"); }
	void	Write(int handle);	
	void	Read(int handle);	
	};

/*
*/
void	SMBasDocSec::Write(int handle)
{
	write(handle, &sign, 1);
	write(handle, &unused, 1);
	write_i16(handle, version);
	write_i16(handle, flags);
	write(handle, name, 64);
}

/*
*/
void	SMBasDocSec::Read(int handle)
{
	read(handle, &sign, 1);
	read(handle, &unused, 1);
	read_i16(handle, version);
	read_i16(handle, flags);
	read(handle, name, 64);
}

/*
*	create a SmallBASIC PDB file
*
*	returns 0 on success
*	-1 can't create file
*	-2 file i/o error
*	-3 text > 32KB
*/
struct txtsec_s	{
	char	name[33];
	char	*sp;
	char	*ep;
	char	*tp;
	int		len;
	};
typedef struct txtsec_s txtsec_t;

int		SaveSBPDB(const char *fname, const char *text)
{
	int			handle;
	PDBHeader	head;
	PDBRecordHeader	rec;
	int32		info;
	SMBasDocSec	sec;
	int16		filler=0;
	char		*final_text, *src, *dst, *ps, *lp;
	txtsec_t	tsec[MAX_SEC+1];
	char		lnx_head[512], lc;
	int			sec_count = 0;
	char		file_name[256];
	int			err_code = 0, i, count;

	// remove '\r'
	final_text = (char *) malloc(strlen(text)+1);
	src = (char *) text;
	dst = final_text;
	while ( *src )	{
		if	( *src != '\r' )	
			*dst ++ = *src;
		src ++;
		}
	*dst = '\0';

	// section list
	src = (char *) final_text;
	if	( strncmp(src, "#!", 2) == 0 )	{
		dst = lnx_head;
		while ( *src != '\0' && *src != '\n' )	
			*dst ++ = *src ++;
		*dst = '\0';
		if	( *src == '\n' )
			src ++;
		strcat(lnx_head, "\n");
		}
	else
		strcpy(lnx_head, "");

	ps = src;
	while ( *src )	{

		if	( strncmp(src, "#sec:", 5) == 0 )	{
			count = 0;
			dst = tsec[sec_count].name;
			tsec[sec_count].tp = src;
			src += 5;
			while ( *src != '\0' && *src != '\n' )	{
				if	( count < 32 )
					*dst ++ = *src ++;
				else
					src ++;
				count ++;
				}
			*dst = '\0';
			if	( *src == '\n' )
				src ++;

			tsec[sec_count].sp = src;
			tsec[sec_count].ep = src;
			sec_count ++;
			ps = src;
			}
		else	{
			// skip text-line
			while ( *src != '\0' && *src != '\n' )	src ++;
			if	( *src == '\n' )
				src ++;
			}
		}

	if	( sec_count == 0 )	{
		strcpy(tsec[0].name, "Main");
		tsec[0].tp = ps;
		tsec[0].sp = ps;
		tsec[0].ep = ps + strlen(ps);
		sec_count ++;
		}

	for ( i = 0; i < sec_count; i ++ )	{
		tsec[i].len = 0;

		if	( (i+1) < sec_count )
			lp = tsec[i+1].tp;
		else
			lp = tsec[i].sp + strlen(tsec[i].sp);

		lc = *lp;
		*lp = '\0';

		if	( i == 0 && strlen(lnx_head) )	
			tsec[i].len += strlen(lnx_head);
		tsec[i].len += strlen(tsec[i].sp);
		tsec[i].len ++;

		if	( tsec[i].len > 32767 )	
			con_printf("\nWarning: section '%s'; size %d > 32KB\n", tsec[i].name, tsec[i].len);

		*lp = lc;
		}

	// base file name < 28 chars + .bas
	#if !defined(_UnixOS)
	src = strrchr((char *) fname, '\\');
	#else
	src = strrchr((char *) fname, '/');
	#endif
	if	( src )	
		src ++;
	else
		src = (char *) fname;

	memset(file_name, 0, 32);	// debug pdb

	strcpy(file_name, src);
	src = strrchr(file_name, '.');
	if	( src )	
		*src = '\0';
	file_name[27] = '\0';		// extention
			
	strcat(src, ".bas");
	strcpy(head.name, file_name);
	
	// create
	remove(fname);
	handle = open(fname, O_CREAT|O_BINARY|O_RDWR, S_IREAD|S_IWRITE);
	if	( handle == -1 )
		err_code = -1;
	else	{
		memcpy(head.type, "TEXT", 4);
		memcpy(head.creator, "SmBa", 4);
		head.counter = sec_count + 1;
		head.Write(handle);

		rec.offset = sizeof(PDBHeader) + sizeof(PDBRecordHeader) * head.counter;
		rec.index ++;
		rec.Write(handle);

		for ( i = 1; i <= sec_count; i ++ )	{
			if	( i == 1 )
				rec.offset += 4;
			else
				rec.offset += (tsec[i-2].len + sizeof(SMBasDocSec));
			rec.index ++;
			rec.Write(handle);
			}

		write_i16(handle, filler);

		info = 0x48030000;		// sign-ver-unused-category
		write_i32(handle, info);
		
		for ( i = 0; i < sec_count; i ++ )	{
			if	( (i+1) < sec_count )
				lp = tsec[i+1].tp;
			else
				lp = tsec[i].sp + strlen(tsec[i].sp);
			lc = *lp;
			*lp = '\0';

			sec.sign = 'S';
			sec.version = 1;
			sec.flags = (i==0) ? 1 : 0;
			strcpy(sec.name, tsec[i].name);
			sec.Write(handle);

			if	( i == 0 && strlen(lnx_head) )	
				write(handle, lnx_head, strlen(lnx_head));
			write(handle, tsec[i].sp, strlen(tsec[i].sp)+1);

			*lp = lc;
			}
		
		close(handle);
		}

	free(final_text);
	return err_code;
}


/*
*	Load a SmallBASIC PDB file
*
*	returns 0 on success
*	-1 can't open file
*	-2 file i/o error
*	-3 text > 32KB
*	-4 bad signature
*/
int		LoadSBPDB(const char *fname, char_p *rtext)
{
	int			handle;
	PDBHeader	head;
	PDBRecordHeader	rec_inf[MAX_SEC+1], rec;
	int32		info;
	SMBasDocSec	sec;
	char		*src, *dst, *buf, *cvbuf, *text;
	char		file_name[256];
	int			err_code = 0, count, i, rcount;

	text = (char *) malloc(MAX_SBTEXT);	
	*text = '\0';
	*rtext = text;

	handle = open(fname, O_BINARY|O_RDWR, S_IREAD|S_IWRITE);
	if	( handle == -1 )
		err_code = -1;
	else	{
		head.Read(handle);
		rcount = head.counter;
		
		for ( i = 0; i < rcount; i ++ )	
			rec_inf[i].Read(handle);

		lseek(handle, rec_inf[0].offset, SEEK_SET);
		read_i32(handle, info);

		
		for ( i = 1; i < rcount; i ++ )	{
			lseek(handle, rec_inf[i].offset, SEEK_SET);

			if	( (info & 0xFFFF0000) == 0x48030000 )	{

				sec.Read(handle);

				buf   = (char *) malloc(0x10000);	// 64KB
				cvbuf = (char *) malloc(0x11000);	// 64KB
				count = read(handle, buf, 0x10000);
				buf[count] = '\0';

				#if	!defined(_UnixOS)
				// add '\r'
				dst = cvbuf;
				src = buf;
				while ( *src )	{
					if	( *src == '\n' )	{
						*dst ++ = '\r';
						*dst ++ = *src ++;
						}
					else
						*dst ++ = *src ++;
					}
				*dst = '\0';
				#else
				strcpy(cvbuf, buf);
				#endif

				// check unix header
				if	( i == 1 )	{
					if	( strncmp(cvbuf, "#!", 2) == 0 )	{
						src = cvbuf;
						dst = text;
						while ( *src != '\0' && *src != '\n' )	
							*dst ++ = *src ++;

						if	( *src )
							src ++;
						*dst ++ = '\n';
						*dst ++ = '\0';
						}
					else
						src = cvbuf;
					}
				else
					src = cvbuf;

				// add section name
				strcat(text, "#sec:");
				strcat(text, sec.name);
				strcat(text, "\n");

				strcat(text, src);
				free(cvbuf);
				free(buf);
				}
			else
				err_code = -4;	// bad signature
			}

		close(handle);
		}

	return err_code;
}


⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?