// 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 #include #include #include #include #include #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->heightheight)return -1; break; case WIDTH: if(p1->width>p2->width)return 1; if(p1->widthwidth)return -1; break; case NARROWNESS: if(p1->narrowness>p2->narrowness)return 1; if(p1->narrownessnarrowness)return -1; break; case WEIGHT: if(p1->weight>p2->weight)return 1; if(p1->weightweight)return -1; break; case FONTTYPE: ft1=(int)p1->fonttype; ft2=(int)p2->fonttype; if(ft1&~3>ft2&~3)return 1; if(ft1&~3facename,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;xflags&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 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