home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS - Coast to Coast
/
simteldosarchivecoasttocoast.iso
/
pcmag
/
vol12n07.zip
/
FNTPRN.ZIP
/
FNTSRC.ZIP
/
ENUMFONT.C
< prev
next >
Wrap
Text File
|
1993-03-16
|
40KB
|
1,210 lines
// Contents copyright (c) 1993 John Deurbrouck
/*
** Define DEBUG for compilation under Borland C++ 3.1 to get a
** standalone test version of ENUMFONT.C
*/
#ifdef DEBUG
int wanna_quit=0;
#endif
/*
** Includes
*/
#include<windows.h>
#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>
#include<commdlg.h>
#include<string.h>
#include"enumfont.h"
/*
** Private Defines
*/
#ifdef DEBUG
#define printf mprintf
#endif
#define FONTHASREGULAR 1
#define FONTHASBOLD 2
#define FONTHASITALIC 4
#define FONTHASBOLDITALIC 8
#define FONTISTRUETYPE 16
#define FONTISFIXEDWIDTH 32
#define MAXALLOCATIONS 100
#define ALLOCATIONSIZE 32000
#define MAXFONTS 512
/*
** Type Definitions
*/
// TRACKFONT struct used to store font data
typedef struct tagTRACKFONT{
LPSTR facename;
int flags;
int height;
int width;
int narrowness;
int weight;
BYTE fonttype;
LPSTR regular,bold,italic,bolditalic;
}TRACKFONT,FAR* LPTRACKFONT;
// TEXTQUEUE for linked list of .WRI file data
typedef struct tagTEXTQUEUE{
LPSTR text;
int textlen;
void FAR* next;
}TEXTQUEUE,FAR* LPTEXTQUEUE;
// WRITEFILEHEADER used to write .WRI header
typedef struct tagWRITEFILEHEADER{
int wIdent;
int dty;
int wTool;
int wReserved[4];
long fcMac;
int pnPara;
int pnFntb;
int pnSep;
int pnSetb;
int pnPgtb;
int pnFfntb;
int szSsht[33];
int pnMac;
int wReserved2[15];
}WRITEFILEHEADER,FAR* LPWRITEFILEHEADER;
// FOD for .WRI file generation
typedef struct tagFOD{
long fcLim;
int bfprop;
}FOD,FAR* LPFOD;
// PAP for .WRI file paragraph data
typedef struct tagPAP{
char len;
char res1;
char just;
}PAP,FAR* LPPAP;
// CHP3, CHP5 for .WRI file character information
typedef struct tagCHP3{
char len;
char res1;
unsigned char bold_it_fontLSBs;
char fontsiz;
}CHP3,FAR* LPCHP3;
typedef struct tagCHP5{
char len;
char res1;
unsigned char bold_it_fontLSBs;
char fontsiz;
char uline;
unsigned char fontMSBs;
}CHP5,FAR* LPCHP5;
/*
** Global Variables
*/
HANDLE instance=0;
HWND hwndSortorder;
HWND hwndDialog;
/* following are user choices to drive file generation */
SORTORDER sortorder=ALPHA;
MONOSPACE monospace=VARMONO;
int use_printer_context=0,allow_synthesis=0,truetype_only=0;
int incl_novelty=0,incl_modern=0,incl_roman=0,
incl_script=0,incl_sanserif=0,incl_other=0;
int incl_regular=0,incl_bold=0,incl_italic=0,incl_bolditalic=0;
int launchwrite=0;
/* following are for internal use of generate_file_from_options() */
static int successful_so_far,did_bailout;// error-occurred variable
static OPENFILENAME ofn;
static HFILE file=HFILE_ERROR;
static int fams; // font families in fonts
static LPTRACKFONT fonts[MAXFONTS];
static HDC hdc;
static FONTENUMPROC do_families,do_individuals;
/* following are for use of get_memory() and free_memory() */
static HGLOBAL mem_handles[MAXALLOCATIONS];
static int mem_handles_used=0,memory_system_restart=0;
// following set by dialog proc, used by generate_file_from_options()
LPSTR sample_text_ptr=0;
int sample_text_length=0;
int sample_text_pointsize=0; // in half-points (24==12pt)
int sample_text_just=0; // JUST_LEFT ... JUST_JUST
LPSTR default_font=0;
BYTE default_ffid=0;
int default_pointsize=0; // in half-points (24==12 pt)
int default_just=0; // JUST_LEFT ... JUST_JUST
int default_bolditalic=0; // BOLD_BIT | ITALIC_BIT
// generate_file_from_options() sets and uses for .WRI file:
LPTEXTQUEUE text_first,text_last;
LPTEXTQUEUE char_first,char_last;
LPTEXTQUEUE graf_first,graf_last;
LPTEXTQUEUE font_first,font_last;
long text_bytes,char_pages,graf_pages,font_pages;
int default_font_offset; // font code for default txt
/*
** Function Prototypes
*/
int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInst,LPSTR cmd,int Show);
static void bailout(char *msg);
int CALLBACK _export families(LPENUMLOGFONT lpelf,TEXTMETRIC FAR* tmptr,
int fonttype,LPARAM lparam);
static LPSTR get_font_type(BYTE pitchandfamily);
int CALLBACK _export individuals(LPENUMLOGFONT lpelf,TEXTMETRIC FAR* tmptr,
int fonttype,LPARAM lparam);
#ifdef DEBUG
int mprintf(const char *fmt,...);
#endif
static void open_output_file(void);
static void gather_data(void);
static void sort_data(void);
static int sorter(const void* arg1,const void* arg2);
static void FAR* get_zeroed_memory(size_t size);
static void FAR* get_memory(size_t size);
static void free_memory(void);
static void generate_report(void);
static void w_init(void);
static void w_default(const char* fmt,...);
static void w_sample(LPTRACKFONT lpf,int bolditalic);
static int w_add_font(LPSTR name, BYTE ffid);
static void w_add_graf(int textlen,int just);
static void w_add_char(int textlen,int bolditalic,int fontcode,int size);
static void w_add_text(LPSTR text,int size);
static void write_data_file(void);
static int write_data_chunk(LPSTR buf,size_t buflen);
static void create_device_context(void);
static void get_user_options(void);
/*
** Function Definitions
*/
#ifdef DEBUG
#pragma argsused
// test scaffolding
int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInst,LPSTR cmd,int Show){
_InitEasyWin();
instance=hInstance;
for(;;){
get_user_options();
if(wanna_quit)break;
generate_file_from_options();
}
return 0;
}
#endif
void generate_file_from_options(void){
// initialize global variables
do_families=do_individuals=NULL;
hdc=NULL;
successful_so_far=1;
did_bailout=0;
fams=0;
// ok, let's get to work
if(successful_so_far)gather_data();
if(successful_so_far)sort_data();
if(successful_so_far)generate_report();
if(successful_so_far)open_output_file();
if(successful_so_far)write_data_file();
if(successful_so_far)bailout(NULL);
else SetFocus(hwndSortorder);
}
// clean up, release memory, device context, etc.
static void bailout(char *msg){
if(did_bailout)return; // don't do this stuff twice
if(msg!=NULL){
MessageBox(hwndDialog,msg,"Error",MB_OK|MB_ICONEXCLAMATION);
successful_so_far=0;
}
if(hdc!=NULL){
DeleteDC(hdc);
hdc=NULL;
}
if(do_families!=NULL){
FreeProcInstance(do_families);
do_families=NULL;
}
if(do_individuals!=NULL){
FreeProcInstance(do_individuals);
do_individuals=NULL;
}
if(file!=HFILE_ERROR){
char buf[270];
_lclose(file);
file=HFILE_ERROR;
if(launchwrite&&successful_so_far){
wsprintf(buf,"WRITE %s",ofn.lpstrFile);
SetFocus(hwndSortorder);
WinExec(buf,SW_SHOWNORMAL);
}
}
free_memory();
}
// families() is the callback function passed to EnumFontFamilies()
// it's called for every font family. for each family of interest,
// families() calls EnumFontFamilies() with individuals() as the
// callback function. this gathers information on presence of
// bold, italic, etc. and puts it into fonts[]
#pragma argsused
int CALLBACK _export families(LPENUMLOGFONT lpelf,TEXTMETRIC FAR* tmptr,
int fonttype,LPARAM lparam){
if(fams==MAXFONTS){
// only nine bits available for font number, so .WRI file
// can't have more than 512 fonts
MessageBox(hwndDialog,"Due to limitations in the .WRI format, "
"only working with first 512 font families.\n\n"
"Assemble several reports to list all your fonts.",
"Too many fonts",MB_OK|MB_ICONINFORMATION);
return 0;
}
// if we don't want non-TT, don't gather this one...
if(truetype_only&&!(fonttype&TRUETYPE_FONTTYPE))return 1;
// if we don't want this font type, don't gather it...
switch(lpelf->elfLogFont.lfPitchAndFamily&~3){
case FF_DECORATIVE: if(!incl_novelty)return 1; break;
case FF_MODERN: if(!incl_modern)return 1; break;
case FF_ROMAN: if(!incl_roman)return 1; break;
case FF_SCRIPT: if(!incl_script)return 1; break;
case FF_SWISS: if(!incl_sanserif)return 1; break;
default: if(!incl_other)return 1; break;
}
// if monospace preference, check it
if(monospace!=VARMONO){
if(lpelf->elfLogFont.lfPitchAndFamily&FIXED_PITCH){
if(monospace==VAR)return 1; // unwanted fixed pitch
}
else{
if(monospace==MONO)return 1;// unwanted var pitch
}
}
// get space and save family information
fonts[fams]=get_memory(sizeof(TRACKFONT));
if(!successful_so_far)return 0;
fonts[fams]->facename=
get_memory(lstrlen(lpelf->elfLogFont.lfFaceName)+1);
if(!successful_so_far)return 0;
lstrcpy(fonts[fams]->facename,lpelf->elfLogFont.lfFaceName);
fonts[fams]->flags=fonttype&TRUETYPE_FONTTYPE?FONTISTRUETYPE:0;
if(lpelf->elfLogFont.lfPitchAndFamily&FIXED_PITCH)
fonts[fams]->flags|=FONTISFIXEDWIDTH;
fonts[fams]->fonttype=lpelf->elfLogFont.lfPitchAndFamily&~3;
// set high value for following; individuals will write in if smaller
fonts[fams]->height=fonts[fams]->width=fonts[fams]->weight=30000;
// set extra style name pointers to NULL
fonts[fams]->regular=fonts[fams]->bold=
fonts[fams]->italic=fonts[fams]->bolditalic=NULL;
// collect the data...
EnumFontFamilies(hdc,lpelf->elfLogFont.lfFaceName,do_individuals,NULL);
// compute narrowness...
if(!successful_so_far)return 0;
fonts[fams]->narrowness=fonts[fams]->width<1?0:
(int)(((float)fonts[fams]->height/(float)fonts[fams]->width)*10.0);
// if allowed, set synthesized style bits, style name pointers
if(allow_synthesis){
if(fonts[fams]->flags&FONTHASREGULAR){
if(!(fonts[fams]->flags&FONTHASBOLD)){
fonts[fams]->flags|=FONTHASBOLD;
fonts[fams]->bold="Synthesized Bold";
}
if(!(fonts[fams]->flags&FONTHASITALIC)){
fonts[fams]->flags|=FONTHASITALIC;
fonts[fams]->italic="Synthesized Italic";
}
}
if(fonts[fams]->flags&FONTHASREGULAR||
fonts[fams]->flags&FONTHASBOLD||
fonts[fams]->flags&FONTHASITALIC){
if(!(fonts[fams]->flags&FONTHASBOLDITALIC)){
fonts[fams]->flags|=FONTHASBOLDITALIC;
fonts[fams]->bolditalic="Synthesized Bold Italic";
}
}
}
// zero out undesired style-present bits
if(!incl_regular) fonts[fams]->flags&=~FONTHASREGULAR;
if(!incl_bold) fonts[fams]->flags&=~FONTHASBOLD;
if(!incl_italic) fonts[fams]->flags&=~FONTHASITALIC;
if(!incl_bolditalic)fonts[fams]->flags&=~FONTHASBOLDITALIC;
// only increment fams if a desired style bit is set
// sure, a little memory is wasted but we'll give it back soon...
if(fonts[fams]->flags&FONTHASREGULAR||
fonts[fams]->flags&FONTHASBOLD||
fonts[fams]->flags&FONTHASITALIC||
fonts[fams]->flags&FONTHASBOLDITALIC)
fams++;
return 1;
}
static LPSTR get_font_type(BYTE pitchandfamily){
switch(pitchandfamily&~3){
case FF_DECORATIVE: return "novelty";
case FF_MODERN: return "modern";
case FF_ROMAN: return "Roman";
case FF_SCRIPT: return "script";
case FF_SWISS: return "sans serif";
default: return "unknown";
}
}
// callback function for EnumFontFamilies()
// called once for each font style in a font (bold, italic, etc.)
// stores information into fonts[]
#pragma argsused
int CALLBACK _export individuals(LPENUMLOGFONT lpelf,TEXTMETRIC FAR* tmptr,
int fonttype,LPARAM lparam){
LPSTR lpstr=NULL;
int truetype=0;
if(!successful_so_far)return 0;
// collect min height, width, weight
if(fonts[fams]->height>lpelf->elfLogFont.lfHeight)
fonts[fams]->height=lpelf->elfLogFont.lfHeight;
if(fonts[fams]->width>lpelf->elfLogFont.lfWidth)
fonts[fams]->width=lpelf->elfLogFont.lfWidth;
if(fonts[fams]->weight>lpelf->elfLogFont.lfWeight)
fonts[fams]->weight=lpelf->elfLogFont.lfWeight;
if(fonts[fams]->flags&FONTISTRUETYPE)truetype=1;
while(truetype){
if(lpelf->elfStyle==NULL)break;
if(lstrlen(lpelf->elfStyle)<1)break;
lpstr=get_memory(lstrlen(lpelf->elfStyle)+1);
if(!successful_so_far)return 0;
lstrcpy(lpstr,lpelf->elfStyle);
break;
}
if(lpelf->elfLogFont.lfItalic){
if(lpelf->elfLogFont.lfWeight>FW_REGULAR){
fonts[fams]->flags|=FONTHASBOLDITALIC;
fonts[fams]->bolditalic=(lpstr==NULL)?"Bold Italic":lpstr;
}
else{
fonts[fams]->flags|=FONTHASITALIC;
fonts[fams]->italic=(lpstr==NULL)?"Italic":lpstr;
}
}
else{
if(lpelf->elfLogFont.lfWeight>FW_REGULAR){
fonts[fams]->flags|=FONTHASBOLD;
fonts[fams]->bold=(lpstr==NULL)?"Bold":lpstr;
}
else{
fonts[fams]->flags|=FONTHASREGULAR;
fonts[fams]->regular=(lpstr==NULL)?"Regular":lpstr;
}
}
return 1;
}
// uses Borland's EasyWin library to write trace file
#ifdef DEBUG
static int mprintf(const char *fmt,...){
char buf[300];
int retval;
va_list ap;
va_start(ap,fmt);
retval=wvsprintf(buf,fmt,ap);
va_end(ap);
#undef printf
if(retval){
if(file!=HFILE_ERROR)_lwrite(file,buf,retval);
else printf(buf);
}
#define printf mprintf
return retval;
}
#endif
// uses Common Dialog Box to get SaveAs filename
// for output .WRI file. defaults to putting file
// into same directory in which FntPrn resides.
static void open_output_file(void){
static char filenamebuffer[256];
char startdir[256];
BOOL ofn_success;
/* initialize ofn structure */
ofn.lStructSize=sizeof(OPENFILENAME);
ofn.hwndOwner=hwndDialog;
ofn.hInstance=instance;
ofn.lpstrFilter=(LPCSTR)"Write Files (*.wri)\0*.wri\0";
ofn.lpstrCustomFilter=NULL;
ofn.nFilterIndex=0;
lstrcpy(filenamebuffer,"fntprn.wri");
ofn.lpstrFile=(LPSTR)filenamebuffer;
ofn.nMaxFile=256;
ofn.lpstrFileTitle=NULL;
if(GetModuleFileName(instance,(LPSTR)startdir,256)){
// first, strip off filename @ end
char *p=startdir,*b=&startdir[3];
while(*p)p++;
while(p>b){
p--;
if(*p=='\\'){*p=0;break;}
*p--=0;
}
ofn.lpstrInitialDir=(LPSTR)startdir;
}
else ofn.lpstrInitialDir=NULL;
ofn.lpstrTitle=(LPSTR)"Choose Output Filename";
ofn.Flags=OFN_HIDEREADONLY|OFN_NOREADONLYRETURN|
OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST;
ofn.lpstrDefExt=(LPSTR)"WRI";
// Allow user to make file selection
ofn_success=GetOpenFileName(&ofn);
if(!ofn_success){
file=HFILE_ERROR;
successful_so_far=0;
bailout(NULL);
return;
}
// Try to open the file
file=_lcreat(ofn.lpstrFile,0);
if(file==HFILE_ERROR)bailout("Could not create file");
}
// fills the fonts[] array
static void gather_data(void){
if(NULL==(do_families=MakeProcInstance(families,instance))){
bailout("Internal Error (families)");
return;
}
if(NULL==(do_individuals=MakeProcInstance(individuals,instance))){
bailout("Internal Error (individuals)");
return;
}
create_device_context();
if(!successful_so_far)return;
EnumFontFamilies(hdc,NULL,do_families,NULL);
if(fams<1){
bailout("No fonts found");
return;
}
if(fams>60){
MessageBox(hwndDialog,"You selected more than 60 fonts.\n\n"
"Write may not display or print them correctly.\n\n"
"Importing this file into a word processor may work better.",
"Caution",MB_OK|MB_ICONINFORMATION);
}
}
// sorter() does the actual work
static void sort_data(void){
if(fams>1)qsort(fonts,fams,sizeof(fonts[0]),sorter);
}
// callback function for qsort()
static int sorter(const void* arg1,const void* arg2){
LPTRACKFONT p1=*(LPTRACKFONT*)arg1,p2=*(LPTRACKFONT*)arg2;
int ft1,ft2;
switch(sortorder){
case HEIGHT:
if(p1->height>p2->height)return 1;
if(p1->height<p2->height)return -1;
break;
case WIDTH:
if(p1->width>p2->width)return 1;
if(p1->width<p2->width)return -1;
break;
case NARROWNESS:
if(p1->narrowness>p2->narrowness)return 1;
if(p1->narrowness<p2->narrowness)return -1;
break;
case WEIGHT:
if(p1->weight>p2->weight)return 1;
if(p1->weight<p2->weight)return -1;
break;
case FONTTYPE:
ft1=(int)p1->fonttype;
ft2=(int)p2->fonttype;
if(ft1&~3>ft2&~3)return 1;
if(ft1&~3<ft2&~3)return -1;
break;
}
// if primary sort is ALPHABETIC or the primary
// sort was a tie (both the same width, for example)
// then sort by font name
return lstrcmpi(p1->facename,p2->facename);
}
// just initializes get_memory() block to zeros
static void FAR* get_zeroed_memory(size_t size){
void FAR* retval;
char FAR* cp;
retval=get_memory(size);
if(retval!=NULL){
cp=retval;
while(size--)*cp++=0;
}
return retval;
}
// elementary suballocator to avoid making tons
// of direct calls to GlobalAlloc()
// memory actually allocated ALLOCATIONSIZE bytes
// at a time, handles stored in mem_handles[]
static void FAR* get_memory(size_t size){
static size_t memory_left;
static char FAR* available_memory;
void FAR* retval;
if(memory_system_restart){
memory_left=0;
memory_system_restart=0;
}
if(size<1)size=1;
while(size>memory_left){
if(mem_handles_used==MAXALLOCATIONS)break;
mem_handles[mem_handles_used]=
GlobalAlloc(GMEM_MOVEABLE,ALLOCATIONSIZE);
if(mem_handles[mem_handles_used]==NULL)break;
available_memory=GlobalLock(mem_handles[mem_handles_used]);
if(available_memory==NULL){
GlobalFree(mem_handles[mem_handles_used]);
break;
}
memory_left=ALLOCATIONSIZE;
mem_handles_used++;
break;
}
if(size>memory_left)bailout("Out of memory");
retval=available_memory;
memory_left-=size;
available_memory+=size;
return retval;
}
// frees the handles in mem_handles[] previously
// allocated by way of get_memory()
static void free_memory(void){
while(mem_handles_used--){
GlobalUnlock(mem_handles[mem_handles_used]);
GlobalFree(mem_handles[mem_handles_used]);
}
mem_handles_used=0;
memory_system_restart=1;
}
// creates .WRI file by first creating the data
// in memory using TEXTQUEUE singly linked lists,
// then writes the file out
static void generate_report(void){
int x;
w_init();
if(!successful_so_far)return;
// write selection data
{
char* sortordername;
char* monospacename;
switch(sortorder){
case HEIGHT:
sortordername="character height";
break;
case WIDTH:
sortordername="character width";
break;
case NARROWNESS:
sortordername="character height divided by character width";
break;
case WEIGHT:
sortordername="character weight";
break;
case FONTTYPE:
sortordername="font family";
break;
default:
sortordername="font name";
break;
}
switch(monospace){
case VAR:
monospacename="Variable pitch only. ";
break;
case MONO:
monospacename="Monospace only. ";
break;
default:
monospacename="";
break;
}
w_default(
"%d font famil%s found%s%s%s%s%s%s."
"%s For %s. "
"Synthetic bold and italic %sallowed%s%s%s%s. "
"%sSorted by %s."
"\r\n",
fams,
(LPSTR)(fams>1?"ies":"y"),
(LPSTR)(incl_roman?", Roman":""),
(LPSTR)(incl_modern?", modern":""),
(LPSTR)(incl_sanserif?", sans serif":""),
(LPSTR)(incl_script?", script":""),
(LPSTR)(incl_novelty?", novelty":""),
(LPSTR)(incl_other?", other/unknown":""),
(LPSTR)(truetype_only?" TrueType only.":""),
(LPSTR)(use_printer_context?"printer":"screen"),
(LPSTR)(((incl_bold||incl_italic||incl_bolditalic)&&allow_synthesis)?"":"not "),
(LPSTR)(incl_regular?", regular":""),
(LPSTR)(incl_bold?", bold":""),
(LPSTR)(incl_italic?", italic":""),
(LPSTR)(incl_bolditalic?", bold-italic":""),
(LPSTR)monospacename,
(LPSTR)sortordername
);
}
// write data for each family
for(x=0;x<fams;x++){
if(!successful_so_far)return;
if(fonts[x]->flags&FONTHASREGULAR)
w_sample(fonts[x],0);
if(!successful_so_far)return;
if(fonts[x]->flags&FONTHASBOLD)
w_sample(fonts[x],BOLD_BIT);
if(!successful_so_far)return;
if(fonts[x]->flags&FONTHASITALIC)
w_sample(fonts[x],ITALIC_BIT);
if(!successful_so_far)return;
if(fonts[x]->flags&FONTHASBOLDITALIC)
w_sample(fonts[x],BOLD_BIT|ITALIC_BIT);
if(!successful_so_far)return;
w_default("*** %s%s%s%s%s%s%s%s%s. %s pitch, %s font "
"family,%s TrueType\r\n",
fonts[x]->facename,
(LPSTR)(fonts[x]->flags&FONTHASREGULAR?", ":""),
fonts[x]->flags&FONTHASREGULAR?fonts[x]->regular:(LPSTR)"",
(LPSTR)(fonts[x]->flags&FONTHASBOLD?", ":""),
fonts[x]->flags&FONTHASBOLD?fonts[x]->bold:(LPSTR)"",
(LPSTR)(fonts[x]->flags&FONTHASITALIC?", ":""),
fonts[x]->flags&FONTHASITALIC?fonts[x]->italic:(LPSTR)"",
(LPSTR)(fonts[x]->flags&FONTHASBOLDITALIC?", ":""),
fonts[x]->flags&FONTHASBOLDITALIC?fonts[x]->bolditalic:(LPSTR)"",
(LPSTR)(fonts[x]->flags&FONTISFIXEDWIDTH?"Fixed":"Variable"),
get_font_type(fonts[x]->fonttype),
(LPSTR)(fonts[x]->flags&FONTISTRUETYPE?"":" not"));
}
}
// sets global variables for .WRI file generation
static void w_init(void){
text_bytes=0;
char_pages=0;
graf_pages=0;
font_pages=0;
text_first=text_last=char_first=char_last=
graf_first=graf_last=font_first=font_last=NULL;
default_font_offset=w_add_font(default_font,default_ffid);
}
// adds a line of data in default_pointsize,
// default_bolditalic, default_font_offset,
// default_just to .WRI file in memory
static void w_default(const char* fmt,...){
LPSTR newtextspace;
static char buf[512]; // for font names, etc.
int retval;
va_list ap;
va_start(ap,fmt);
retval=wvsprintf(buf,fmt,ap);
va_end(ap);
if(!retval)return;
newtextspace=get_memory(retval);
if(!successful_so_far)return;
lstrcpy(newtextspace,buf);
w_add_char(retval,default_bolditalic,default_font_offset,
default_pointsize);
w_add_graf(retval,default_just);
w_add_text(newtextspace,retval);
}
// adds a line of data in the specified font to
// the .WRI file in memory. used to add the actual
// sample text (AENOPS, the alphabet, whatever) to
// the report
static void w_sample(LPTRACKFONT lpf,int bolditalic){
int fontcode=w_add_font(lpf->facename,lpf->fonttype);
w_add_char(sample_text_length,bolditalic,fontcode,sample_text_pointsize);
w_add_graf(sample_text_length,sample_text_just);
w_add_text(sample_text_ptr,sample_text_length);
}
// adds a new font to the .WRI file in memory
// this is the set of font names at the end of
// the file
static int w_add_font(LPSTR name, BYTE ffid){
static int cur_bytes_left;
static LPSTR previous_name=NULL;
static char FAR* next_byte;
static int FAR* numptr;
int bytes_to_use=3+lstrlen(name)+1;
int bytes_needed=bytes_to_use+2;
int FAR* fpi;
// don't duplicate last request...
if(name==previous_name)return *numptr-1;
else previous_name=name;
if(font_first==NULL){
font_first=get_memory(sizeof(TEXTQUEUE));
if(!successful_so_far)return 0;
font_first->text=get_zeroed_memory(0x80);
if(!successful_so_far)return 0;
font_first->textlen=0x80;
font_first->next=NULL;
cur_bytes_left=0x7E;
font_last=font_first;
numptr=(int FAR*)font_first->text;
next_byte=&font_first->text[2];
*numptr=0;
font_pages++;
}
if(bytes_needed>cur_bytes_left){
if(bytes_needed>0x70){
bailout("Windows reports too-long font name");
}
fpi=(int FAR*)next_byte;
*fpi=-1; // mark last block
font_last->next=get_memory(sizeof(TEXTQUEUE));
if(!successful_so_far)return 0;
font_last=font_last->next;
font_last->text=get_zeroed_memory(0x80);
if(!successful_so_far)return 0;
font_last->textlen=0x80;
font_last->next=NULL;
cur_bytes_left=0x80;
next_byte=font_last->text;
font_pages++;
}
fpi=(int FAR*)next_byte;
*fpi=bytes_to_use-2;
next_byte[2]=ffid&~3;
lstrcpy(&next_byte[3],name);
next_byte+=bytes_to_use;
cur_bytes_left-=bytes_to_use;
*numptr+=1;
return *numptr-1;
}
// used to add new text data to the .WRI file
// in memory
static void w_add_graf(int textlen,int just){
static int cur_bytes_left;
static char FAR* next_byte;
static char FAR* fod_count;
int total_bytes_needed;
FOD fod;
PAP pap;
LPPAP lppap;
if(graf_first==NULL){
graf_first=get_memory(sizeof(TEXTQUEUE));
if(!successful_so_far)return;
graf_last=graf_first;
graf_last->text=get_zeroed_memory(0x80);
if(!successful_so_far)return;
graf_last->textlen=0x80;
graf_last->next=NULL;
cur_bytes_left=0x7B;
next_byte=&graf_last->text[4];
((long FAR*)next_byte)[-1]=text_bytes+0x80;
fod_count=&graf_last->text[127];
graf_pages++;
}
pap.len=sizeof(PAP)-1;
pap.res1=0;
pap.just=(unsigned char)just;
total_bytes_needed=sizeof(FOD)+sizeof(PAP);
if(total_bytes_needed>cur_bytes_left){
graf_last->next=get_memory(sizeof(TEXTQUEUE));
if(!successful_so_far)return;
graf_last=graf_last->next;
graf_last->text=get_zeroed_memory(0x80);
if(!successful_so_far)return;
graf_last->textlen=0x80;
graf_last->next=NULL;
cur_bytes_left=0x7B;
next_byte=&graf_last->text[4];
((long FAR*)next_byte)[-1]=text_bytes+0x80;
fod_count=&graf_last->text[127];
graf_pages++;
}
cur_bytes_left-=sizeof(PAP);
lppap=(LPPAP)(next_byte+cur_bytes_left);
*lppap=pap;
fod.bfprop=(char FAR*)lppap-(char FAR*)graf_last->text-4;
fod.fcLim=text_bytes+textlen+0x80;
*(LPFOD)next_byte=fod;
next_byte+=sizeof(FOD);
cur_bytes_left-=sizeof(FOD);
*fod_count+=1;
}
// used to add character data to the .WRI file in memory
static void w_add_char(int textlen,int bolditalic,int fontcode,int size){
static int cur_bytes_left;
static char FAR* next_byte;
static char FAR* fod_count;
int total_bytes_needed;
FOD fod;
CHP5 chp5;
LPCHP5 lpchp5;
LPCHP3 lpchp3;
if(char_first==NULL){
char_first=get_memory(sizeof(TEXTQUEUE));
if(!successful_so_far)return;
char_last=char_first;
char_last->text=get_zeroed_memory(0x80);
if(!successful_so_far)return;
char_last->textlen=0x80;
char_last->next=NULL;
cur_bytes_left=0x7B;
next_byte=&char_last->text[4];
((long FAR*)next_byte)[-1]=text_bytes+0x80;
fod_count=&char_last->text[127];
char_pages++;
}
chp5.res1=0;
chp5.bold_it_fontLSBs=(unsigned char)((fontcode<<2)|bolditalic);
chp5.fontsiz=(unsigned char)size;
chp5.uline=0;
chp5.fontMSBs=(unsigned char)(fontcode>>6);
chp5.len=chp5.fontMSBs?sizeof(CHP5)-1:sizeof(CHP3)-1;
total_bytes_needed=sizeof(FOD)+(chp5.fontMSBs?sizeof(CHP5):sizeof(CHP3));
if(total_bytes_needed>cur_bytes_left){
char_last->next=get_memory(sizeof(TEXTQUEUE));
if(!successful_so_far)return;
char_last=char_last->next;
char_last->text=get_zeroed_memory(0x80);
if(!successful_so_far)return;
char_last->textlen=0x80;
char_last->next=NULL;
cur_bytes_left=0x7B;
next_byte=&char_last->text[4];
((long FAR*)next_byte)[-1]=text_bytes+0x80;
fod_count=&char_last->text[127];
char_pages++;
}
if(chp5.fontMSBs){
cur_bytes_left-=sizeof(CHP5);
lpchp5=(LPCHP5)(next_byte+cur_bytes_left);
*lpchp5=chp5;
fod.bfprop=(char FAR*)lpchp5-(char FAR*)char_last->text-4;
}
else{
cur_bytes_left-=sizeof(CHP3);
lpchp3=(LPCHP3)(next_byte+cur_bytes_left);
*lpchp3=*(LPCHP3)&chp5;
fod.bfprop=(char FAR*)lpchp3-(char FAR*)char_last->text-4;
}
fod.fcLim=text_bytes+textlen+0x80;
*(LPFOD)next_byte=fod;
next_byte+=sizeof(FOD);
cur_bytes_left-=sizeof(FOD);
*fod_count+=1;
}
// adds report data to .WRI file in memory, appending
// to text_first queue
static void w_add_text(LPSTR text,int size){
if(text_first==NULL){
text_first=get_memory(sizeof(TEXTQUEUE));
if(!successful_so_far)return;
text_last=text_first;
}
else{
text_last->next=get_memory(sizeof(TEXTQUEUE));
if(!successful_so_far)return;
text_last=text_last->next;
}
text_last->text=text;
text_last->textlen=size;
text_last->next=NULL;
text_bytes+=size;
}
// now all data is prepared in memory, so write it all
// out. header first, then report contents, then character
// data, then paragraph data, then font names
static void write_data_file(void){
long text_pages;
LPWRITEFILEHEADER wfh=get_zeroed_memory(sizeof(WRITEFILEHEADER));
if(!successful_so_far)return;
wfh->wIdent=0xBE31;
wfh->wTool=0xAB00;
wfh->fcMac=text_bytes+0x80;
{ // pad the text to 128-byte boundary
int bytes_needed=0x80-text_bytes%0x80;
LPSTR newspace;
if(bytes_needed){
newspace=get_zeroed_memory(bytes_needed);
if(!successful_so_far)return;
w_add_text(newspace,bytes_needed);
if(!successful_so_far)return;
}
text_pages=text_bytes/0x80;
}
wfh->pnPara=1+text_pages+char_pages;
wfh->pnFntb=wfh->pnSep=wfh->pnSetb=wfh->pnPgtb=wfh->pnFfntb=
1+text_pages+char_pages+graf_pages;
wfh->pnMac=1+text_pages+char_pages+graf_pages+font_pages;
// write header
if(!write_data_chunk((LPSTR)wfh,sizeof(WRITEFILEHEADER)))return;
{ // write text
LPTEXTQUEUE l=text_first;
while(l){
if(!(write_data_chunk(l->text,l->textlen)))return;
l=l->next;
}
}
{ // write char data
LPTEXTQUEUE l=char_first;
while(l){
if(!(write_data_chunk(l->text,l->textlen)))return;
l=l->next;
}
}
{ // write graf data
LPTEXTQUEUE l=graf_first;
while(l){
if(!(write_data_chunk(l->text,l->textlen)))return;
l=l->next;
}
}
{ // write font data
LPTEXTQUEUE l=font_first;
while(l){
if(!(write_data_chunk(l->text,l->textlen)))return;
l=l->next;
}
}
}
// helper function for write_data_file()
static int write_data_chunk(LPSTR buf,size_t buflen){
if(file==HFILE_ERROR||!successful_so_far)return 0;
if((UINT)buflen!=_lwrite(file,buf,buflen)){
bailout("Error writing file");
return 0;
}
return 1;
}
// need device context for EnumFontFamilies()
static void create_device_context(void){
if(use_printer_context){ // based on Petzold 3rd ed., p. 707
char pr[100];
char *dev,*driver,*output;
GetProfileString("windows","device","",pr,sizeof(pr));
if((dev=strtok(pr,","))==NULL||
(driver=strtok(NULL,", "))==NULL||
(output=strtok(NULL,", "))==NULL)
bailout("Printer driver information unavailable");
else{
hdc=CreateIC(driver,dev,output,NULL);
if(hdc==NULL)bailout("Internal Error (printer context)");
}
}
else{
hdc=CreateIC("DISPLAY",NULL,NULL,NULL);
if(hdc==NULL)bailout("Internal Error (display context)");
}
}
// all the rest is test scaffolding to create text-mode Win
// app to test file generation code
#ifdef DEBUG
#include<conio.h>
static void get_user_options(void){
int failure;
wanna_quit=1;
for(;;){
failure=0;
printf("want to quit now? (y/n): ");
switch(getch()){
case 'y': case 'Y': wanna_quit=1; return;
case 'n': case 'N': wanna_quit=0; break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("sort order (a)lpha, (h)eight, (w)idth, "
"(n)arrowness, w(e)ight, (f)onttype: ");
switch(getch()){
case 'a': case 'A': sortorder=ALPHA; break;
case 'h': case 'H': sortorder=HEIGHT; break;
case 'w': case 'W': sortorder=WIDTH; break;
case 'n': case 'N': sortorder=NARROWNESS; break;
case 'e': case 'E': sortorder=WEIGHT; break;
case 'f': case 'F': sortorder=FONTTYPE; break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("monospace (m)ono (v)ariable (b)oth: ");
switch(getch()){
case 'm': case 'M': monospace=MONO; break;
case 'v': case 'V': monospace=VAR; break;
case 'b': case 'B': monospace=VARMONO; break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("use_printer_context? (y/n): ");
switch(getch()){
case 'y': case 'Y': use_printer_context=1;break;
case 'n': case 'N': use_printer_context=0;break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("allow_synthesis? (y/n): ");
switch(getch()){
case 'y': case 'Y': allow_synthesis=1;break;
case 'n': case 'N': allow_synthesis=0;break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("truetype_only? (y/n): ");
switch(getch()){
case 'y': case 'Y': truetype_only=1;break;
case 'n': case 'N': truetype_only=0;break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("incl_novelty? (y/n): ");
switch(getch()){
case 'y': case 'Y': incl_novelty=1;break;
case 'n': case 'N': incl_novelty=0;break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("incl_modern? (y/n): ");
switch(getch()){
case 'y': case 'Y': incl_modern=1;break;
case 'n': case 'N': incl_modern=0;break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("incl_roman? (y/n): ");
switch(getch()){
case 'y': case 'Y': incl_roman=1;break;
case 'n': case 'N': incl_roman=0;break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("incl_script? (y/n): ");
switch(getch()){
case 'y': case 'Y': incl_script=1;break;
case 'n': case 'N': incl_script=0;break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("incl_sanserif? (y/n): ");
switch(getch()){
case 'y': case 'Y': incl_sanserif=1;break;
case 'n': case 'N': incl_sanserif=0;break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("incl_other? (y/n): ");
switch(getch()){
case 'y': case 'Y': incl_other=1;break;
case 'n': case 'N': incl_other=0;break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("incl_regular? (y/n): ");
switch(getch()){
case 'y': case 'Y': incl_regular=1;break;
case 'n': case 'N': incl_regular=0;break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("incl_bold? (y/n): ");
switch(getch()){
case 'y': case 'Y': incl_bold=1;break;
case 'n': case 'N': incl_bold=0;break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("incl_italic? (y/n): ");
switch(getch()){
case 'y': case 'Y': incl_italic=1;break;
case 'n': case 'N': incl_italic=0;break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
for(;;){
failure=0;
printf("incl_bolditalic? (y/n): ");
switch(getch()){
case 'y': case 'Y': incl_bolditalic=1;break;
case 'n': case 'N': incl_bolditalic=0;break;
default: failure=1;
}
printf("\n");
if(!failure)break;
}
sample_text_ptr="PANOSE abegmoqstfy\r\n";
sample_text_length=lstrlen(sample_text_ptr);
sample_text_pointsize=20;
sample_text_just=JUST_JUST;
default_font="Arial";
default_ffid=FF_SWISS;
default_pointsize=14;
default_just=JUST_LEFT;
default_bolditalic=0;
}
#endif