diff options
Diffstat (limited to 'support/TeX4ht/source/tex4ht-c.tex')
-rw-r--r-- | support/TeX4ht/source/tex4ht-c.tex | 17542 |
1 files changed, 17542 insertions, 0 deletions
diff --git a/support/TeX4ht/source/tex4ht-c.tex b/support/TeX4ht/source/tex4ht-c.tex new file mode 100644 index 0000000000..04a0116680 --- /dev/null +++ b/support/TeX4ht/source/tex4ht-c.tex @@ -0,0 +1,17542 @@ +% $Id: tex4ht-c.tex 417 2018-06-30 22:36:42Z karl $ +% tex tex4ht-c +% Copyright 2009-2018 TeX Users Group +% Copyright 1996-2009 Eitan M. Gurari +% Released under LPPL 1.3c+. +% See tex4ht-cpright.tex for license text. + +\def\MSVCI{} +\def\MSVCI{NO} + + \def\export{ } + +\input common + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + \input DraTex.sty \input AlDraTex.sty + \input tex4ht.sty + \Preamble{html,th4,family,sections+,xhtml} + \EndPreamble + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\expandafter \ifx \csname append:def\endcsname \relax + \expandafter\def\csname append:def\endcsname#1#2{% + \def\Xtemp{\def#1}% + \expandafter\expandafter\expandafter\Xtemp\expandafter{#1#2}} +\fi + +\expandafter \ifx \csname Verbatim\endcsname \relax + \def\Verbatim{\bgroup + \catcode`\^=10 \catcode`\\=10 \catcode`\%=10 + \catcode`\{=10 \catcode`\}=10 \catcode`\#=10 \catcode`\#=10 + \XVerbatim} + \long\def\XVerbatim#1EndVerbatim{\egroup} +\fi + +\expandafter \ifx \csname Verb\endcsname \relax + \def\Verb{\bgroup \catcode`\^=10 \catcode`\\=10 \catcode`\%=10 + \catcode`\{=10 \catcode`\}=10 \catcode`\#=10 \catcode`\#=10 + \leavevmode \Xctgs} + \def\Xctgs#1{\def\Xeat##1#1{\egroup}\Xeat } +\fi + +\ifx \HAssign\UnDef + +\csname newcount\endcsname \tmpXxXcnt + +\def\advXxX#1{\def\XxXvar{#1}\futurelet\XxXtemp\AdvancXxX} +\def\AdvancXxX{\ifx [\XxXtemp \expandafter\AdvancXxXe + \else \expandXxXafter{\expandafter\advXxXc\XxXvar}\fi} +\def\AdvancXxXe[#1]{\expandafter\advXxXc\csname + \expandafter\string\XxXvar[#1]\endcsname} + +\def\gXxXAdvance#1{\bgroup \def\XxXtemp{#1}% + \tmpXxXcnt#1\afterassignment\XxXgplus \mthXxXop\tmpXxXcnt} +\def\XxXgplus{\expandafter\xdef\XxXtemp{\the\tmpXxXcnt}\egroup} +\def\XxXAdvance#1{\bgroup \def\XxXtemp{#1}% + \tmpXxXcnt#1\afterassignment\XxXaplus \mthXxXop\tmpXxXcnt} +\def\XxXaplus{\xdef\XxXtemp{\def\expandafter\noexpand\XxXtemp{\the\tmpXxXcnt}}% + \egroup \XxXtemp} +\def\HAssign{\XxXssg\edef} +\def\gHAssign{\XxXssg\xdef} + +\def\XxXssg#1#2{\let\dXxXfn#1\def\XxXvar{#2}\futurelet\XxXtemp\XxXAssgn} +\def\XxXAssgn{% + \ifx [\XxXtemp + \expandafter\dXxXfn\XxXvar[##1]{% + \noexpand\csname \expandafter + \string\XxXvar[##1]\noexpand\endcsname}% + \expandafter\assgXxXm + \else \afterassignment\assgXxXv \expandafter \tmpXxXcnt \fi } + +\def\assgXxXv{\expandafter\dXxXfn\XxXvar{\the\tmpXxXcnt}} +\def\assgXxXm[#1]{% + \def\XxXtemp{\expandafter\dXxXfn + \csname \expandafter\string\XxXvar[#1]\endcsname{\the\tmpXxXcnt}}% + \afterassignment\XxXtemp \tmpXxXcnt} + +\fi +\catcode`\:=11 +\csname newcount\endcsname\tmp:cnt +\expandafter\ifx \csname no:catcodes\endcsname\relax + \def\no:catcodes#1#2#3{% + \tmp:cnt=#1 + \def\no::catcodes{% + \catcode\tmp:cnt=#3 + \ifnum\tmp:cnt<#2 + \advance\tmp:cnt by 1 \expandafter\no::catcodes + \fi }% + \no::catcodes } +\fi +\let\:oldlq=\` +\let\:oldrq=\' +\def\'{\leavevmode \:cats \::cats} +\def\::cats#1{\if #1"\expandafter\:oldrq + \else \def\:eat##1#1{\tt ##1\egroup}\expandafter\:eat\fi} +\def\`{\leavevmode \:cats \:::cats} +\def\:::cats#1{\if #1"\expandafter\:oldlq + \else \def\:eat##1#1{`{\tt ##1}'\egroup}\expandafter\:eat\fi} +\bgroup + \catcode`\^=7 + \gdef\:cats{\bgroup \no:catcodes0{255}{12}\catcode`\ = 10 + \catcode`\^^M = 10 \catcode`\^^I = 10 + } +\egroup +\catcode`\:=12 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\input ProTex.sty + +\ifHtml \AlProTex{c,<<<>>>,`,title,list,ClearCode,_^,CodeLineNo} + + \let\coDE=\< + \def\<{\vfil\par\coDE} + +\else \AlProTex{c,<<<>>>,`,title,list,[],ClearCode,_^} +\fi + + +\font\CommentFont=cmitt10 +\def\?{\CommentFont} + + +\ifHtml + + +\TocAt{Chapter,Section,SubSection,LikeSection,/Appendix,/Part} +\TocAt{Appendix,Section,SubSection,LikeSection,/Chapter,/Part} + +%\CutAt{+Part} +\CutAt{Chapter,Part,Appendix} +\CutAt{Appendix,Part,Chapter} + +\EveryChapter{\TocChapter % [\Link[\jobname toc.html]{}{}Expanded toc\EndLink] + } +\EveryAppendix{\TocAppendix %[\Link[\jobname toc.html]{}{}Expanded toc\EndLink] + } + +\expandafter\let\expandafter\oldbye\expandafter=\csname bye\endcsname + +\expandafter\gdef\csname bye\endcsname{% + \FileStream{\jobname toc.html}% + \TableOfContents + \EndFileStream{\jobname toc.html}% + \csname oldbye\endcsname} + +\else +\hbadness=10000 \vbadness=10000 \hfuzz=99in \vfuzz=99in + +\catcode`\:=11 + +\def\ChildOf{} +\def\ro:nd#1{} +\def\HRefPort\<#1\>{} + + + + + + + + + + + + +\catcode`\:=12 + +\fi + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% \ChildOf[ChapterCounter]{tex4ht} + + +\ifx \export\:UnDef \else \def\CodeId#1#2{} \fi + + + +\def\UnderLine#1{\ifHtml +% \IgnorePar\EndP + \HCode{<strong>}#1\HCode{</strong>}\else\underbar{#1}\fi} +\let\CModifyShowCode=\ModifyShowCode +\let\CModifyOutputCode=\ModifyOutputCode +\def\ModifyShowCode{\def\[##1({##1\UnderLine{(}}\def\;{\UnderLine{;}}\CModifyShowCode} +\catcode`\^=7 +\catcode`\@=6 \catcode`\#=12 \catcode`\^^M=13\relax% +\def\ModifyOutputCode{% +\def\;{ SEP }% +\def\[@@1(@@2)@@3;{@@1 +#ifdef ANSI +#define SEP , +(@@3) +#undef SEP +#else +#define SEP ; +(@@2)@@3; +#undef SEP +#endif +}% +\CModifyOutputCode}% +\catcode`\^^M=5 +\catcode`\@=12 +\catcode`\#=6 +\catcode`\^=13 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\Part{tex4ht.c} + + +\TableOfContents[Chapter,Appendix,Section,LikeSection] + +\Chapter{Flow of Program} + +\input tex4ht-cpright + +\Section{Preamble} + +A command-line program running in the console environment of the +operating system (MS-DOS, MS-DOS window of Windows 3.1, Unix shell, +etc). The input is a heavily specialized DVI file. The main output is +the HTML/XML and \`'.css', also \`'.lg', \`'.idv', and +\`'.tmp'. + +\<tex4ht.c\><<< +/* tex4ht.c (`version), generated from `jobname.tex + Copyright 2009-2018 TeX Users Group + Copyright `CopyYear.1996. Eitan M. Gurari +`<TeX4ht copyright`> */ +`<tex4ht.h`> +>>> + + + + + + + +\<tex4ht.h\><<< +/* Compiler options (uncommented | command line), as comments: + + Classic C (CC) default +#define ANSI ansi-c, c++ +#define DOS_C +#define HAVE_STRING_H <string.h> +#define HAVE_DIRENT_H <dirent.h> +#define HAVE_SYS_NDIR_H <sys/ndir.h> +#define HAVE_SYS_DIR_H <sys/dir.h> +#define HAVE_NDIR_H <ndir.h> +#define HAVE_IO_H <io.h> +#define HAVE_UNISTD_H <unistd.h> +#define WIN32 +#define KPATHSEA +#define CDECL ....... +#define BCC32 bordland c++ + +************************************************* + Tex4ht variables * + (uncommented | command line) * +----------------------------------------------- */ +`<h-defines`> +/* ******************************************** */ +`<define MSVC-1-52`> +`<bordland: bcc32 -DBCC32 tex4ht`> +`<bordland: bcc -DBCC -mh tex4ht`> +`<DJGPP`> +#ifdef DOS_C +#define DOS +#endif +#ifdef DOS +#define DOS_WIN32 +#define HAVE_STRING_H <string.h> +#endif +#ifdef WIN32 +#define DOS_WIN32 +#ifndef KPATHSEA +#define HAVE_STRING_H <string.h> +#endif +#endif +`<h-defines DOS-WIN32`> +`<h-defines KWIN32`> +`<h-include`> +`<h-defines 2`> +>>> + +% lint tex4ht.c -DHAVE_DIRENT_H -DHAVE_STRING_H + +\<bordland: bcc32 -DBCC32 tex4ht\><<< +#ifdef BCC32 +#define DOS_WIN32 +#define ANSI +#define HAVE_DIRENT_H +#define PLATFORM "ms-win32" +#endif +>>> + +The \`'-mh' below calls for `Huge Memory Model'. + +\<bordland: bcc -DBCC -mh tex4ht\><<< +#ifdef BCC +#define DOS_C +#define ANSI +#define HAVE_DIRENT_H +#define PLATFORM "ms-dos" +#ifndef PATH_MAX +#define PATH_MAX 256 +#endif +#endif +>>> + + + +\ifHtml[\HPage{more}\Verbatim +> 1) I think there is a bug in Tex4ht (perhaps in the Dos'port), because +> it doesn't find the .tfm files when they are in different directories +> (with the ! at the end of the "tc:d:\share\texmf\fonts\tfm!"). I am +> obliged to put all the files in a common directory. + +The directory search has been disabled for the DOS port with +the following code. + +#define DOS +#define NOSUBDIR +#endif + +I'm not sure the decision to disable recursive searches was a good one, +and I'll probably reinstate recursive searches in the next version. + +If you compiled the source code, instead of downloading an executable +application, try recompiling the source, after removing the above +segment of code. + +\EndVerbatim\EndHPage{}]\fi + + microsoft visual c options: msdos application (.exe), large, ss=sd + +\Verbatim +#define MSVC_1_52_DOS +#define MSVC_1_52_DOS_LIB not fully implemented +------------------------------------------------------------ + End options --- Start comments * +------------------------------------------------------------ +MSVC_1_52_DOS: * + MS-DOS appl (project type), release (buld mode), * + huge, ss==ds, 80286, no debug * + no sub directories (missing opendir,closedir, readdir) * +MSVC_1_52_DOS_LIB: * + as above, but opendir,closedir, readdir compiled * + with tex4ht * +------------------------------------------------------------ + End comments +\EndVerbatim + + +\<h-include\><<< +#ifdef KPATHSEA +#include <kpathsea/config.h> +#endif +#include <stdio.h> `% EOF, FILE `% +#include <stdlib.h> `% EXIT_FAILURE `% +>>> + +\<defines\><<< +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif +>>> + +\<h-include\><<< +#ifdef HAVE_STRING_H +#include <string.h> +#endif +>>> + + + + + + + + + + Under ANSI C, all malloc stuff is declared in \`'<stdlib.h>' (which you +also include), hence this non-standard header is redundant. + + +\SubSection{MSVC-1-52-DOS} + + +\<define MSVC-1-52\MSVCI\><<< +#ifdef MSVC_1_52_DOS_LIB +#define MSVC_1_52_DOS +#endif +#ifdef MSVC_1_52_DOS +#define DOS +#define NOSUBDIR +#endif +#ifdef MSVC_1_52_DOS_LIB +#undef NOSUBDIR +#endif +>>> + +\<if not-def MSVC-1-52\MSVCI\><<< +#ifndef MSVC_1_52_DOS +>>> + +\<endif not-def MSVC-1-52\MSVCI\><<< +#endif +>>> + + + + + +\SubSection{KPATHSEA Windows} + + + + + + +% #define NOSUBDIR + +% MSVC_1_52_DOS -> DOS, NOSUBDIR, not <dirent.h> + +% ANSI --> PROTOTYPE +% DOS -> <string.h> + + + + + + + +\<h-defines KWIN32\><<< +#ifdef KPATHSEA +#ifdef WIN32 +#define KWIN32 +#endif +#endif +>>> + + +Here are the promised patch. However I have not yet tested it very +much. It is unlikely that I test it with non-kpathsea setting. At +least the patch compiles in both kpathsea and non-kpathsea setting. + The following patch is very similar +to some code in kpathsea / web2c. + + +\<h-include\><<< +#ifdef WIN32 +#ifdef KPATHSEA +#undef CDECL +#define CDECL __cdecl +#else +#include <windows.h> +#endif +#else +#ifdef KPATHSEA +#define CDECL +#endif +#endif +>>> + +\<if not-WIN32\><<< +#ifndef WIN32 +>>> + +\<endif not-WIN32\><<< +#endif +>>> + + + +\<header functions\><<< +#ifdef WIN32 +static BOOL sigint_handler(ARG_I(DWORD)); +#endif +>>> + +\<functions\><<< +#ifdef WIN32 + + +`[ +static BOOL sigint_handler(dwCtrlType) DWORD dwCtrlType +;{ + `<avoid warning of unused dwCtrlType`> + err_i(32); + return FALSE; `% return value obligatory `% +} +#endif +>>> + +\<avoid warning of unused dwCtrlType\><<< +if( dwCtrlType ){ (IGNORED) printf(" "); } +>>> + + +\<CDECL\><<< +#ifdef CDECL +CDECL +#endif +>>> + + + +Forgetting \`'_pascal' and \`'_cdecl' modifiers: Each C function may +be either \`'_pascal' or \`'_cdecl'. This modifier defines how +parameters are passed to it. Default for Smalltalk definition is +\`'_cdecl'. Default for C functions depends on compiler settings, and +you can use other types uncompatible with Smalltalk. In Windows API +16-bit functions are \`'_pascal' and 32-bit \`'_cdecl'. + + + +The following Shared across recursive calls, it acts like a stack. + + + +\<vars\><<< +#ifdef WIN32 +static U_CHAR dirname[PATH_MAX]; +#endif +>>> + +Recursive directory search relies on some Windows API similar to +opendir/readdir + +\<file = search WIN32 subdir (name,str)\><<< +{ + WIN32_FIND_DATA find_file_data; + HANDLE hnd; + int proceed; + (IGNORED) strcpy((char *) dirname, (char *) str); + strct(dirname, "/*.*"); `% "*.*" or "*" -- seems equivalent. `% + hnd = FindFirstFile(dirname, &find_file_data); + if (hnd != INVALID_HANDLE_VALUE) { + `<valid WIN32 handle`> + } +} +>>> + +\<valid WIN32 handle\><<< +proceed = 1; +while (proceed) { + if( !eq_str(find_file_data.cFileName, ".") && + !eq_str(find_file_data.cFileName, "..") ) + { + (IGNORED) strcpy((char *) str+n, (char *) find_file_data.cFileName ); + str[n-1] = dir_path_slash(str); + if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if( (file = search_file_ext(name, str, flags)) != NULL ){ + FindClose(hnd); + return file; } + } + } + proceed = FindNextFile(hnd, &find_file_data); +} +FindClose(hnd); +>>> + + +SIGFPE is handled by the C library, SIGSEGV too but not generated by +the system, so it does nothing but is harmless + +SetConsoleCtrlHandler is need to catch Ctrl+C and Ctrl+Break under +Windows, SIGINT is not generated by the system. + +\<KWIN32 signals\><<< +SetConsoleCtrlHandler((PHANDLER_ROUTINE)sigint_handler, TRUE); +>>> + + + + + + +\SubSection{DJGPP} + + +\Verbatim + + * tex4ht.c [__DJGPP__] (ANSI, DOS_GIF_FILE): Define. + (LSTAT): Define to stat for every system that doesn't define + S_ISLNK. + (WRITE_BIN_FLAGS, READ_BIN_FLAGS): Use binary mode with DJGPP. + (dos_file_names): New variable. + [WIN32] (sigint_handler): Add missing semi-colon in prototype + declaration. + (sig_err): If got fatal signal other than SIGINT or SIGQUIT, don't + return to caller, since the program will be aborted otherwise. + (search_file_ext): Allow use of both forward- and back-slashes on + DOS and Windows platforms. + (insert_ch) [DOS_GIF_FILE]: Only use butchered file name if long + file names aren't supported (dos_file_names is TRUE). + (main) [KPATHSEA]: If input is from stdin which is not a console + device, switch it to binary mode. Set dos_file_names to TRUE for + all DOS platforms, FALSE on Unix and WIN32, and compute at runtime + for DJGPP. Simplify logic of finding the init file by pushing + HOME=C: into environment if $HOME isn't defined on DOSISH systems. + Only use butchered file names for GIF files if long file names + aren't supported (dos_file_names is TRUE). +\EndVerbatim + + + +\<DJGPP\><<< +#ifdef __DJGPP__ +#define DOS_WIN +#define ANSI +#ifndef HAVE_STRING_H +#define HAVE_STRING_H 1 +#endif +#endif +>>> + +\<vars\><<< +static BOOL dos_file_names = +#ifdef DOS_GIF_FILE + TRUE +#else + FALSE +#endif +; +>>> + + + + Set dos\_file\_names to TRUE for + all DOS platforms, FALSE on Unix and WIN32, and compute at +runtime + for DJGPP. + +\<DJGPP gif names for pictorial symbols\><<< +#if !defined(DOS_GIF_FILE) && !defined(WIN32) && defined(__DJGPP__) + dos_file_names = !_use_lfn(NULL); +#endif +>>> + + +\<extra options\><<< +switch( *(p+2) ){ + case 's':{ dos_file_names = TRUE; break; } + default:{ bad_arg; } +} +>>> + + +\Verbatim + + > The diffs are attached below. The first hunk is because HAVE_STRING_H is + > already defined by c-auto.h that's generated by configure, and GCC + > complained about redefinition. The second hunk just moves the call to + > _use_lfn to a place where the variable "name" is defined. _use_lfn needs + > an actual file name as argument, because the support for long file names + > is determined dynamically for each filesystem. (There can be cases where + > you run on Windows 9X, where DJGPP supports long file names, but one or + > more of the file names passed to tex4ht reside on some networked drive + > mounted with a network client which doesn't support long file names.) + + + + +> Now, do we want tex4ht to propose a long and a short name for each +> output file, and determine in each case which of the two names to +> assign according to whether `use_lfn(name)' accepts the long name? + +That's what I had in mind, yes. + +The philosophy behind that is that DJGPP executables should use long +file names whenever they are available. However, given that there are +several different filesystems accessible from the machine (via a +network), long names might be supported by some of these filesystems, +but not by others. So the DJGPP version needs to decide whether or +not to use the long name for every command-line argument it processes, +since each such argument can belong to a different filesystem. + +For example, suppose tex4ht.exe is invoked like this: + + tex4ht c:/foo/bar/baz.dvi d:/dvi/xyz.dvi + +If the C: drive supports long file names, but D: does not (because it +is mounted by a network software which doesn't support long file +names), my intent was that tex4ht will behave differently with each +file. + + +This feature turns out to be too expensive to utilize in tex4ht.c. +The problem is that tex4ht first creates the html files from the dvi +source, and during this phase it determines which pictorial symbols +are needed. The gif files of the pictorial symbols get their names +during this phase. However, the gif files themselves are created only +at the end of the compilation, after all the names have been already +determined and used. + + +Anyway, the fallback should be to determine the value of dos_file_names +(sp?) once, in the beginning of `main', by calling _use_lfn(NULL). This +checks long file name support by the default filesystem, which is usually +a good indication of other filesystems as well. + + + +Corrections to my previous email: + +In the first phase, tex4ht.c extracts the html code from the dvi file +and, along this process, determines the names of the gif files for the +pictorial symbols in use. The following code fragement is responsible +for getting the names. + + if( !dos_file_names ){ + print_f(font_tbl[cur_fnt].name); + if( mag == 10 ) (IGNORED) sprintf(str, GIF_I, design_ch, gif); + else (IGNORED) sprintf(str, GIF_II, mag, design_ch, + gif); + } + +In the second phase, tex4ht.c creates a dvi page for each of the +pictorial symbols in use, places the code in the idv file, and puts in +the lg file requests for translating the dvi pages into gif files of +the specified names. The file names are provided by the following +code. + + if( !dos_file_names ){ + if( mag == 10 ) (IGNORED) sprintf(str, ``%s-%x%s'', + font_tbl[cur_fnt].name, ch, gif); + else (IGNORED) sprintf(str, ``%s-%x-%x%s'', + font_tbl[cur_fnt].name, mag, ch, gif); + } + +tex4ht.c never gets to create the gif files. Instead, t4ht.c scans +the lg file, and use that information to invoke auxiliary tools for +translating the dvi pages into gif files. + + + +Added also a command line switch -xs to allow forcing of short names +for the gif files. +\EndVerbatim + + +\<DJGPP signals\><<< +#ifdef __DJGPP__ + if (s != SIGINT && s != SIGQUIT) + exit(EXIT_FAILURE); +#endif +>>> + +\SubSection{Compatibity} + +\Verbatim + > The style file provides a set of commands for requesting html code. + > The user may insert these commands to the source code, and tex4ht will + > use them to create the desired output. I placed a more detailed + > overview with examples in + > http://www.cse.ohio-state.edu/~gurari/temp/XXX/ + + I've downloaded the Essential Tex example, and managed to convert it +(sort of). There are a few problems with file name lengths - I had to +rename the file to es.tex to get it to be processed properly. According +to the .lg file I should have a lot of es.idv[xx] files; since DOS only +supports 3 character extentions, they had all overwritten each other +(truncating the extention to .idv), so I only had one file. Trying to +view this file made my driver complain that it was corrupt (it lacked a +postamble). + + Basically, most of the functionality seems to work under DOS, but the +file naming conventions appear to be a problem. If you want a more +detailed report of the problems, let me know. + + > I have no problems dealing with C code, but I'm not familiar with the + > different standards (including ANSI C) and libraries that exist + > around. I'll need to overcome this deficiency to make tex4ht.c a + > portable utility. + + I've been following comp.lang.c for quite a while now, which focuses +strongly on portable (ANSI) C, so I have some insight in that. If you +solely use the ANSI C library functions (which should be possible, I +think), you don't need to worry about portability - any conforming +compiler can generate the code. For example, I noticed that your code +includes: + + + Under ANSI C, all malloc stuff is declared in <stdlib.h> (which you +also include), hence this non-standard header is redundant. + + Looking a bit better at the source code, I found that I could rid +myself of all the prototype problems by defining ARG. For ANSI, this +should be the default. If you really want to go for ANSI, you can get +rid of all these ARG_I macro's and fully and unconditionally prototype +everything. + +All of the "const is long" warnings can be fixed by appending a "L" +after all constants bigger than 32767. The "conversion may loose +significant digits" warnings appear to be related with indexing arrays +with longs - I haven't figured this one out yet, as far as I know ANSI +allows this. (DOS compilers generally don't support it, though - I can +just turn off this warning). + + A few warnings result from using an assignment inside an if-clause, +mostly with file opening code (e.g. "if(name = fopen(stuff)){file is +open}"). Changing this to an explicit comparison to NULL ("if((name = +fopen(stuff)) != NULL)") kills the warnings while allowing the compiler +to warn you when you typed "=" where you ment "==". + + One last thing I noticed: after other attempts at opening "tex4ht.env" +have failed, you try to open "C:\.tex4ht". Since DOS doesn't allow files +with no name (only an extention), and the maximum size of the extention +is 3 chars anyway, this will always fail - so this code can be deleted. + + > I'll get an ANSI C compiler for my PC, and will fix tex4ht.c to deal + > also with that standard. I'll might ask your advice regarding + > searching directories and files on pc's, but if this will be the case + > I'll prepare a small toy example capturing the features I need. + + You may be used to stuff like opendir/readdir/closedir; I believe +there is code in the snippets maintained by Bob Stout that emulates +these calls under DOS. If you place this stuff in a separate module, +your main code can remain portable (it is a good idea to separate the +non-portable stuff from the portable code). + + Note that a port of gcc to DOS exists (djgpp), which eliminates many +of the porting problems. It still would be nice if it compiled +error-free on my native DOS compiler, though. + +\EndVerbatim + + +\Verbatim + Good - I'm glad that I'm of some help. The code snippet you sent me +compiled without a single warning here, so you're on the right track +(although stuff like stat() isn't ANSI, it appears supported by a lot of +compilers). + + I compiled the source with the defines DOS and ANSI - and most of it +worked. You forgot the terminating quote for "tex4ht.env on line 1715. I +also get warnings that denominator and numerator are not being used +(only assigned to) and, from the source, the warning appears to be +correct. + + If I turn on my compilers ANSI flag, I have a few problems. First, +your function declarations are still in K&R style C. Although ANSI +allows that, it prohibits type checking, and gives some problems with +argument promotion. Specifically, the function insert_ch_map() gives +problems. Your declaration looks like this (I reformatted it a bit for +readability ;-): + +void insert_ch_map(ch, tag) + char ch; + BOOL tag; +{ /* etc */ + + Changing this to the normal ANSI definition shuts up my compiler: + +void insert_ch_map(char ch, BOOL tag) { /* etc */ + + I suggest that you change your other function definitions to ANSI +style too (if you still want to go for ANSI, that is). + + Another problem I ran into is that _fileno is unavailable to both +compiler and linker if I turn on ANSI compilation. I checked where you +use it, and it is in only one place, to find the file length of the DVI +file. Your code: + + struct STSTAT temp; + (IGNORED) fstat (fileno(dvi_file), &temp); + file_len = (long) temp.st_size; + if( (file_len % 4) != 0 ) bad_dvi; + +If you change this to use ftell and fseek, you'll have gained ANSI +compatibility (and therewith portability). I tried the following code +instead of yours: + + long curr_pos; + + curr_pos = ftell(dvi_file); + fseek(dvi_file, 0, SEEK_END); + file_len = ftell(dvi_file); + fseek(dvi_file, curr_pos, SEEK_SET); + if( (file_len % 4) != 0 ) bad_dvi; + + To the best of my nowledge, this works exactly like your code (I +tested it). My executable is compiled with this code. + + I've found other non-ANSI stuff that you may want to remove; if you'd +like me to check for it (and, if I can, suggest an ANSI alternative), +let me know. I've found at least access() - I haven't looked into how to +do that portably. + + > With the new versions of the tools, and the parameter `htm' (instead of + > `html') in \Preamble, the full name gentle.tex can be used. + + Yes, this appears to be working now. + + > A line of the form + + > -+- needs -+- es.idv[xx] ==> abc.gif -+- + + > in the .lg file asks that the xx'th page of es.idv will be translated + > into a gif picture and be stored in file abc.gif. + + OK, I misunderstood that. I will hold off looking into the picture +translation for a bit - but this seems like a job for perl. There is a +DOS port of perl, and I'm just familiarizing myself with it. I don't +know if the port is able to launch sub-processes. If not, I could +probably come up with an awk or perl script that creates a batch file to +do the job. (Requiring awk may be nicer than requiring perl, since the +DOS port of awk is only a little over 90 KB, while perl is seven times +as large). Alternatively, you could perhaps change the format of the lg +file a bit, to contain lines like: + +convert es.idv xx abc.gif + +i.e., provide the required information as dvi file, page number, and +output filename on the commandline of "convert" (or however you want to +call it). This could that be used almost without effort as shell script +or batch file. + + > After getting your last email, I bought Turbo C++ 4.5 for windows (I + > couldn't find one for dos without reaching to a very fat system). I + > tried the attached program in different modes, including ANSI C, and + > to my surprise opendir/readdir/closedir worked fine. + + Here too. Strange. Opendir etc is not ANSI, but it is Posix - and +apparently Borland added some posix stuff to their libraries. I'm not +sure if you should stick with them or not. I haven't studied that part +of your source code yet, so I can't say if it can be easily ANSIfied. If +we stick with this, and later you want to port to Apple, Amiga, +whatever, you're probably in trouble. + + > That left me even more puzzled to why my version of MSVC doesn't + > support these functions. + + They're Posix - a Unix standard. Apparently they felt is wasn't +appropriate for DOS. + + A few notes on the working of tex4ht.sty: Some of my code doesn't +compile because I have \label{}s inside sectioning commands. LaTeX +itself does allow this. Also, all headings are links to themselves - +why? + + Below, I included a LaTeX source that both your code and LaTeX2HTML +can't seem to translate properly - but then, I hardly know anything of +the possibilities of tex4ht.sty. Have you started any form of +documentation yet? (I don't read TeX, only LaTeX, so looking at the sty +file myself didn't help much). + + + +\documentclass[11pt]{article} +\usepackage{alltt} + +%% Environment to typeset screen text, menus etc. in: verbatim-style +%% and boxed. + +\newsavebox{\scrntxt} +\newenvironment{boxedfig}[2]% + % First argument is width of box, second is caption text + { \newcommand{\capt}{#2}% To transport caption to end of environment + \begin{minipage}[b]{#1}% + \begin{lrbox}{\scrntxt}\begin{minipage}{\textwidth}% + \fontsize{10}{11}\selectfont\begin{alltt}% + } % + { \end{alltt}\end{minipage}\end{lrbox}\setlength{\fboxsep}{3pt}% + \framebox[\textwidth][l]{\usebox{\scrntxt}}\caption{\capt}% + \end{minipage}% + } + +\begin{document} + +Below you will find two figures. They are boxed neatly, and typeset in a +fixed-width font of a size independent of the main font size. + +\begin{figure}[htb] +\begin{boxedfig}{0.495\textwidth}{The MBR 1 boot menu\label{bootmenu:1}} +Please select partition too boot. +Choose from: + +1. 123456789AB +2. 123456789AB +3. 123456789AB +4. 123456789AB + +? +\end{boxedfig}\hfill +\begin{boxedfig}{0.495\textwidth}{The MBR 2 boot menu\label{bootmenu:2}} +Please select partition too boot. +Choose from: + +1. 12345678 +2. 12345678 +3. 12345678 +4. 12345678 + +Boot? +\end{boxedfig} +\end{figure} + +I want to be able to reference both +figure~\ref{bootmenu:1} and figure~\ref{bootmenu:2} from my HTML file. +How to achieve this? + +\end{document} + +\EndVerbatim + +\<defines\><<< +#if INT_MAX < 2147483647L `%2^31`% +#define LONG L +#endif +>>> + +Lint does not like non-null pointers to be cast. +\`'free(void *)' instead of \`'free()' will make lint to stop +complaining, but is this really the problem. For this function we have a +definition \`'void free(void *)'. + + +\`'1<<20' should be \`'1L<<20' for short integer. + +Integers on Dos they are just 16 bits!!! Also, ordering of bytes is +inconsistence. + + + + + +\<h-include\><<< +#include <limits.h> `% INT_MAX `% +>>> + +\<defines\><<< +#ifdef LONG +#define INTEGER long +#else +#define INTEGER int +#endif +#define U_CHAR char +>>> + + + + + + +\Verbatim +string.h: extern int strlen( ); +string.h: extern size_t strlen(char *); +string.h: extern size_t strlen(const char *); +string.h: extern size_t strlen( ); + +void * realloc( void *, size_t) +\EndVerbatim + + +\<resplit argv for windows\><<< +#ifdef WIN32 + /* The idea here is to split options apart at spaces: a single argument + "-foo -bar" becomes the two options "-foo" and "-bar". We need to + do this for Windows because mk4ht passes this sort of combined + option in one string to scripts like htlatex.{unix,bat}. In the + Unix case, the shell resplits words when calling t4ht and tex4ht, + so the program see two options. But this does not happen with the + .bat; %4, for instance, remains "-foo -bar". So we fix it here. */ + if (argc > 2) { + int i, nargc; + char **nargv, **pnargv, **pargv; + + nargv = (char **) xmalloc (2 * argc * sizeof (char *)); + pnargv = nargv; + pargv = argv; + *pnargv++ = xstrdup (*pargv++); + *pnargv++ = xstrdup (*pargv++); + nargc = 2; + + for (i=2; i < argc; i++) { + char *p, *q, *r; + p = q = *pargv++; + while (*p == ' ' || *p == '\t') { + p++; + q++; + } + while (*p != ' ' && *p != '\t' && *p) { + p++; + if (*p == '\0') { + *pnargv++ = xstrdup(q); + nargc++; + } else if (*p == ' ' || *p == '\t') { + r = p; + while (*p == ' ' || *p == '\t') + p++; + if (*p == '-' || *p == '\0') { + *r = '\0'; + *pnargv++ = xstrdup(q); + nargc++; + q = p; + } + } + } + } + + nargv[nargc] = NULL; + argv = nargv; + argc = nargc; + } +#endif +>>> + + +\SubSection{Signals} + +\<h-include\><<< +#include <signal.h> +>>> + +\<header functions\><<< +static void +`<CDECL`> +sig_err(ARG_I(int)); +>>> + + + + +\<functions\><<< +`[ +static void +`<CDECL`> +sig_err(s) int s +;{ + (void) signal(s,SIG_IGN); `%ignore the signal`% + switch( s ){ +#ifdef SIGSEGV + case SIGSEGV: err_i(30); +#endif + case SIGFPE : err_i(31); +#if defined(SIGINT) && !defined(WIN32) + case SIGINT : err_i(32); +#endif + } + `<DJGPP signals`> +} +>>> + +DJGPP:(sig\_err): If got fatal signal other than SIGINT or SIGQUIT, don't + return to caller, since the program will be aborted otherwise. + + + + +\<set signals\><<< + +#ifdef SIGSEGV + (void) signal(SIGSEGV,sig_err); +#endif + (void) signal(SIGFPE,sig_err); +#ifdef WIN32 + `<KWIN32 signals`> +#else +#ifdef SIGINT + (void) signal(SIGINT,sig_err); `%Control-c, user interrupt`% +#endif +#endif +>>> + + +SIGSEGV, SIGILL, SIGTERM not implemented in MS-DOS. They are supplied just for +compatibility. Looks like that SIGINT is defined for windows but not for dos. +\ifHtml[\HPage{more}\Verbatim + Eitan> I also wonder whether the WIN32 really needs to discard the + Eitan> following code fragment. + +signal() is supported through the standard libc, but is mostly +ineffective. An example of the kind of code needed is attached. + + +/* Interrupt handler. mt_exit() is a cleanup_and_exit function */ +#ifdef _WIN32 +BOOL sigint_handler(DWORD dwCtrlType) +{ + mt_exit(3); + return FALSE; /* return value obligatory */ +} +#else +void sigint_handler (int sig) +{ + mt_exit(3); +} +#endif + + /* Catch signals, so we clean up if the child is interrupted. + This emulates "trap 'whatever' 1 2 15". */ +#ifdef _WIN32 + SetConsoleCtrlHandler((PHANDLER_ROUTINE)sigint_handler, TRUE); +#else +# ifdef SIGINT + signal (SIGINT, sigint_handler); +# endif +# ifdef SIGHUP + signal (SIGHUP, sigint_handler); +# endif +# ifdef SIGTERM + signal (SIGTERM, sigint_handler); +# endif +#endif +\EndVerbatim\EndHPage{}]\fi + +Msvc recommends not using printf, but we ignoring this recommendation +here with the assumption that the recommendation relates to I/O +interrupts that are not considered here. + +\<signals messages: 30-32\><<< +"Illegal storage address\n", `%30 segmentation`% +"Floating-point\n", `%31 `% +"Interrupt with Cntr-C\n", `%32 `% +>>> + + + +\Section{Kpathsea} + + +\<KPATHSEA h-include\><<< +#ifdef KPATHSEA +#include <kpathsea/c-errno.h> +#include <kpathsea/c-ctype.h> +#include <kpathsea/c-fopen.h> +#include <kpathsea/c-pathmx.h> +#include <kpathsea/proginit.h> +#include <kpathsea/tex-file.h> +#include <kpathsea/tex-make.h> +#include <kpathsea/variable.h> +#include <signal.h> +#if !defined(_AMIGA) && !defined(WIN32) +#include <sys/time.h> +#endif +#include <fcntl.h> +#include <setjmp.h> +#endif `%/* KPATHSEA */`% +>>> + +\List{*} +\item +The \`'__cdecl' is defined in KPATHSEA: kpathsea/c-protos.h +is defined to nothing for compilers +other than MS. +\item +Compiling for kpathsea: +\List{*} +\item Download \Link[http://www.xs4all.nl/\string +~infovore/tex4htk.tgz]{}{}{http://www.xs4all.nl/\string +~infovore/tex4htk.tgz}\EndLink. +\item At texk, issue the commands \`'./configure' and \`'make'. +\EndList +\item +In the presence of kpathsea, there is no reason for the explicit +t-records in tex4ht.env. All tex4ht needs is just the information +available to latex about the tfm files, and kpathsea already embeds +it. +\item +To my understanding, the value of @texmf@ is known to kpathsea within +some variable (TEXMF?). The value of that variable can be accessed by +tex4ht through \`'kpse_var_value( "TEXMF" )'. So i-records similar to the +following ones may provide to tex4ht the information needed to locate +the files. + +\Verbatim + ikpatsea{TEXMF}\tex4ht\ht-fonts\ + ikpatsea{.....}\tex4ht\ht-fonts\ + +\EndVerbatim + +Of course, I rather have texht request kpathsea to perform the search, +but I don't know how to request it through a command similar to the +following one. + +\Verbatim + extended_kpse_find_file(filename, var, path, ...) + ^^^ + "TEXMF" + ^^^^^ + "\tex4ht\ht-fonts\" +\EndVerbatim + +I don't yet follow the details of \`'client_path' but I suspect it might +provide support for instructions similar to the above. + +\EndList + + + + + + + +%%%%%%%%%%%%%%%%%% +\Section{Outline} +%%%%%%%%%%%%%%%%%% + +\<tex4ht.c\><<< +`<defines`> +`<types`> +`<vars`> +`<header functions`> +`<functions`> +`[ +int `<CDECL`> main(argc, argv) + int argc`; + U_CHAR **argv +;{ `<main's vars`> + `<resplit argv for windows`> + `<set signals`> + `<program signature`> + `<init traces`> + `<main's init`> + `<main's body`> + return 0; +} +>>> + +The operating system claims that +`Compilation exited abnormally with code 255' even on cases that +come back through return. why? Was this corrected? + + + + +\<program signature\><<< +(IGNORED) printf("----------------------------\n"); +#ifndef KPATHSEA +#ifdef PLATFORM + (IGNORED) printf("tex4ht.c (`version %s)\n",PLATFORM); +#else + (IGNORED) printf("tex4ht.c (`version)\n"); +#endif +#else +#ifdef PLATFORM + (IGNORED) printf("tex4ht.c (`version %s kpathsea)\n",PLATFORM); +#else + (IGNORED) printf("tex4ht.c (`version kpathsea)\n"); +#endif +#endif +for(i=0; i<argc; i++){ + (IGNORED) printf("%s%s ", (i>1)?"\n " : "", argv[i]); } +(IGNORED) printf("\n"); +>>> + + +\SubSection{Main's Body} + + +\<main's body\><<< +{ long file_len; + `<scan job args`> + `<find tex4ht.env`> + `<get from tex4ht.env file`> + `<file-len = size of file`> + `<open log file`> + `<export TEX4HTFONTSET`> + `<scan postamble`> + (IGNORED) fclose(dot_file); +} +`<scan preamble`> +`<scan pages`> +put_char('\n');put_char('\n'); +`<close active output files`> +{ `<idv vars`> + `<extract dvi chunks`> } +>>> + + + +\<vars\><<< +static FILE* dot_file; +>>> + +\<main's vars\><<< +register INTEGER i; +int ch; +>>> + + +\SubSection{Utilities} + + + + +\<defines\><<< +#define m_alloc(typ,n) (typ *) malloc_chk((int) ((n) * sizeof(typ))) +>>> + + + +\<header functions\><<< +static void* malloc_chk(ARG_I(int)); +>>> + +\<functions\><<< +`[ +static void* malloc_chk( n ) int n +;{ void* p; + if((p = (void *) malloc( (size_t) n)) == NULL ) bad_mem; + return p; +} +>>> + + + + +\<header functions\><<< +static void* r_alloc(ARG_II(void *, size_t)); +>>> + +\<functions\><<< +`[ +static void* r_alloc( q, n ) + void *q`; + size_t n +;{ void* p; + if((p = (void *) realloc( q, (size_t) n)) == NULL) bad_mem; + return p; +} +>>> + +\Section{Installers and Makefiles} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Command Line Switches} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% q, * + +\<scan job args\><<< +{ int i; + U_CHAR *p; + const U_CHAR *in_name = "", *out_name = ""; + `<kpathsea arg 0`> + `<DJGPP gif names for pictorial symbols`> + if( argc == 1 ){ bad_arg; } + for(i=1; i<argc; i++) { + if( *( p=argv[i] ) == '-' ){ `<scan flaged args`> } + else in_name = argv[i]; + } + `<post scan comm ln args`> + `<open input file`> + { `<pre open output file`> } +} +>>> + + +If \`'strlen() argv[i] ) == 2' the switch is followed by a +space to be deleted when more input is awaited. + + + + + +\<scan flaged args\><<< +if( (int) strlen((char *) argv[i] ) == 2 ){ + if( ++i == argc ) bad_arg; +} +switch( *(p+1) ){ + case 'b':{ `<get start char-gif from com ln`> break; } + case 'c':{ `<env blocks selector`> break;} + case 'e':{ `<get .env directory from com ln`>break; } + case 'f':{ `<get file name wo dir`>break; } + case 'F':{ `<get ignored chars`> break; } + case 'g':{ `<get gif-type from com ln`> break; } + case 'h':{ `<trace context`> break; } + case 'i':{ `<get htf font dir from com ln`> break; } + case 'l':{ `<get tex4ht.fls from com ln`> break; } + case 'P':{ `<permission for system calls`> break; } + case 'S':{ `<get gif script from com ln`> break; } + case 's':{ `<get cascade style sheet data`> break; } + case 't':{ `<get tfm font dir from com ln`> break; } + case 'u':{ `<get unicode entity representations`> break; } + case 'v':{ `<idv version replacement num`> break; } + case 'x':{ `<extra options`> break; } + case '.':{ `<default extension`> break; } + default:{ bad_arg; } +} +>>> + + + +The following is to allow for commands \`'htlatex +-f/../source/foo.tex' which draw files from other directories for +latex, but use the current directory for tex4ht.c (and t4ht.c). The +character immediately after \`'-f' is a directory indicator character. +The \`'-f/' requests a search for the indicated file to take place in +the current directory, not in a remote one. + +\<get file name wo dir\><<< +p = p + 2; +in_name = p + (int) strlen((char *) p ); +while( *in_name != *p ){ in_name--; } +in_name++; +>>> + + +Suboptions for \`'-h'. + +\<trace context\><<< +{ + char trace = *(p+2); + if (trace == 'A' || trace == 'e') { `<context for warn and errs`> } + if (trace == 'A' || trace == 'f') { `<dump htf files`> } + if (trace == 'A' || trace == 'F') { `<trace htf search`> } + if (trace == 'A' || trace == 's') { `<trace specials in dvi`> } + if (trace == 'A' || trace == 'g') { `<cmd line trace groups`> } + if (trace == 'A' || trace == 'v') { `<dump env file`> } + if (trace == 'A' || trace == 'V') { `<trace env search`> } + else { bad_arg; } +} +>>> + +The following is incomplete!!! + + +\<command line options\><<< +"improper command line\ntex4ht [-f<path-separator-ch>]in-file[.dvi]\n" +" [-.<ext>] replacement to default file extension name .dvi\n" +" [-c<tag name>] choose named segment in env file\n" +" [-e<env-file>]\n" +" [-f<path-separator-ch>] remove path from the file name\n" +" [-F<ch-code>] replacement for missing font characters; 0--255; default 0\n" +" [-g<bitmap-file-ext>]\n" +" [-h[efFgsvVA]] trace: e-errors/warnings, f-htf, F-htf search\n" +" g-groups, s-specials, v-env, V-env search, A-all\n" +" [-i<htf-font-dir>]\n" +" [-l<bookkeeping-file>]\n" +" [-P(*|<filter>)] permission for system calls: *-always, filter\n" +" [-S<image-script>]\n" +" [-s<css-file-ext>] default: -s4cs; multiple entries allowed\n" +" [-t<tfm-font-dir>]\n" +" [-u10] base 10 for unicode characters\n" +" [-utf8] utf-8 encoding for unicode characters\n" +" [-v<idv version>] replacement for the given dvi version\n" +" [-xs] ms-dos file names for automatically generated gifs\n" +>>> + + + +Line breaks within command lines should be physically given. + +\Section{I/O Files} + +\<defines\><<< +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif +>>> + + +\Verbatim + ../html.dir/a.out a -s"--- needs --- %%1.idv[%%2] ==> %%3 --- +" -b"--- characters --- +\EndVerbatim + +\SubSection{Open Input} + +\<vars\><<< +static FILE* dvi_file; +>>> + +\<main's init\><<< +dvi_file = stdin; +>>> + + + +Below: If input is from stdin which is not a console + device, switch it to binary mode. + +Warning `statement with no effect' under \`'gcc -Wall' on non-Windows. +This is not a problem; SET_BINARY is a no-op. + +\<open input file\><<< +if( *in_name != '\0' ){ `<file = non-piped input file`> } +#ifdef KWIN32 + else if (!isatty(fileno(stdin))) SET_BINARY(fileno(stdin)); +#endif +>>> + + +\<file = non-piped input file\><<< + BOOL tag; +job_name_n = (int) strlen( in_name ); +job_name = m_alloc(char, job_name_n+6); +(IGNORED) strcpy((char *) job_name, in_name); +tag = job_name_n < 3; +if( !tag ){ + tag = !eq_str( job_name+job_name_n-`<dvi ext name length`>,`<dvi ext name`>); +} +if( tag ){ + job_name_n+=`<dvi ext name length`>; (IGNORED) strct(job_name, `<dvi ext name`>); +} +if( (dvi_file = fopen(job_name, READ_BIN_FLAGS)) == NULL ) + { `<try jobname with extension`> } +`<open idv file`> +>>> + + +\<dvi ext name length\><<< +( + (ext==NULL)? 4 : (int) strlen((char *) ext) +) +>>> + +\<dvi ext name\><<< +( + (ext==NULL)? ".dvi" : ext +) +>>> + + + + +\<vars\><<< +static U_CHAR *ext = NULL; +>>> + + +\<default extension\><<< +ext = p+1; +>>> + + + + +The following tries to remove an extension from the filename, +before adding the `.dvi' extension. +This can help with ht scripts of the form + +\Verbatim + $1 $2 + $1 $2 + $1 $2 + tex4ht $2 + t4ht $2 +\EndVerbatim + +in cases that the users insert for \`'$2' file names with extension. + +\<try jobname with extension\><<< +{ int i; + for(i=job_name_n-5; i; i--){ + if( job_name[i] == '.' ){ + job_name[i] = '\0'; + job_name_n = i + `<dvi ext name length`>; + (IGNORED) strct(job_name, `<dvi ext name`>); + break; + } } + if( (dvi_file = fopen(job_name, READ_BIN_FLAGS)) == NULL ){ + warn_i_str(1, job_name); bad_in_file(job_name); +} } +>>> + + +\<vars\><<< +static char* job_name; +static int job_name_n; +>>> + + +strcat should be in string.h, but c++ doesn't find it there. +We use it just for concatenating an extension of +file name. Should have the interface +\`'char *strcat( (char *, const U_CHAR *) );'. + +\<header functions\><<< +static void strct( ARG_II(char *, const U_CHAR *) ); +>>> + +\<functions\><<< +`[ +static void strct( str1, str2 ) + U_CHAR * str1`; + const U_CHAR * str2 + +;{ U_CHAR * ch; + ch = str1 + (int) strlen((char *) str1); + (IGNORED) strcpy((char *) ch, str2 ); +} +>>> + + +\SubSection{Open Root Html File} + +\<pre open output file\><<< + U_CHAR *name=0; +if( *out_name == '\0' ) + { if( *in_name == '\0' ){ `<name = "tex4htput.html"`> } + else { `<name = derived from input file name`> } + } +else{ `<name = output file from arg list`> } +no_root_file = name; +>>> + +We want to wait with actually opening the file output file until the +last minute, to allow a special to change the extension name from the +tex file. That last minute is taken to be when a cll to openning +ort closing a file occurs, or when output is to be written into the file. + +\<open output file\><<< +if( no_root_file ){ open_o_file(); } +>>> + + +\<header functions\><<< +static void open_o_file( ARG_I(void) ); +>>> + +\<functions\><<< +static void open_o_file(MYVOID) +{ + `<open root tex4ht file`> + cur_o_file = root_file = open_html_file(no_root_file); + no_root_file = (char *) 0; +} +>>> + +% free((void *) no_root_file); + +\<open root tex4ht file\><<< + struct files_rec* p; +p = m_alloc(struct files_rec, 1); +if( opened_files != (struct files_rec*) 0 ) opened_files->prev = p; +p->prev = (struct files_rec *) 0; +p->next = opened_files; opened_files = p; +p->name = no_root_file; +p->file = +>>> + + + + +\<cond insert new line\><<< +if( !no_root_file ){ + `<end text accent`> + if( !`<radical-line-off`> ){ put_char('\n'); } +} +>>> + + + + + +\<change ext of root file\><<< +if( no_root_file ){ + U_CHAR *name; + name = m_alloc(char, 256); + (IGNORED) strcpy((char *) name, (char *) no_root_file ); + free((void *) no_root_file); + no_root_file = name; + name += (size_t) strlen((char *) name); while( *(--name) != '.' ); name++; + while( special_n-- ){ + if( (no_root_file+253) == name ) name--; + *name++ = get_char(); + } + *name = '\0'; +} else { + U_CHAR str[256], *p; + p = str; while( special_n-- ){ *p++ = get_char(); } *p = '\0'; + warn_i_str(43,str); +} +>>> + +\<vars\><<< +static U_CHAR *no_root_file; +>>> + + + +\<name = "tex4htput.html"\><<< +bad_arg; +>>> + + +\<name = derived from input file name\><<< +int n = (int) strlen((char *) job_name ); +name = m_alloc(char, 6 + n); +(IGNORED) strcpy((char *) name, (char *) job_name); +n -= 4; *(name + n) = '\0'; +(IGNORED) strct(name,".html"); +#ifdef HTM +name[n+4] ='\0'; +#endif +>>> + + + + + + + + +\<name = output file from arg list\><<< + int tag = 1; + int n = (int) strlen( out_name ); +name = m_alloc(char, 6 + n); +(IGNORED) strcpy((char *) name, out_name); +while( n-- ) tag = tag && (*(name+n) != '.') ; +if( tag ) (IGNORED) strct(name,".html"); +#ifdef HTM +name[n+4] = '\0'; +#endif +>>> + +\<header functions\><<< +static FILE* open_html_file( ARG_I(char*) ); +>>> + +\<functions\><<< +`[ +static FILE* open_html_file(name) + char* name +;{ FILE* file; + char* str; + str = m_alloc(char, (int) strlen((char *) name) + 1); + (IGNORED) strcpy((char *) str, (char *) name); + (IGNORED) printf(" file %s\n", str); + (IGNORED) fprintf(log_file, "File: %s\n", str); + if( (file = fopen(str, WRITE_TEXT_FLAGS)) == NULL ) bad_in_file(str); + free((void *) str); + return file; +} +>>> + +\<vars\><<< +static FILE *out_file = (FILE *) 0, + *root_file = (FILE *) 0, + *cur_o_file = (FILE *) 0; +>>> + + + + +\SubSection{Close Output} + +\<close active output filesNO\><<< +if( root_file != (FILE *) 0 ) (IGNORED) fclose(root_file); +>>> + +\SubSection{Get Input-File Length} + +Files must have length divisible by four and have 4 to 7 \`'trail' characters. + + + + + + Another problem I ran into is that fileno is unavailable to both +compiler and linker if I turn on ANSI compilation. I checked where you +use it, and it is in only one place, to find the file length of the DVI +file. Your code: + +\Verbatim +{ struct STSTAT temp; + (IGNORED) fstat (fileno(dvi_file), &temp); + file_len = (long) temp.st_size; + if( (file_len % 4) != 0 ) bad_dvi; +} +\EndVerbatim + +If you change this to use ftell and fseek, you'll have gained ANSI +compatibility (and therewith portability). I tried the following code +instead of yours: + +\<file-len = size of file\><<< +{ long curr_pos; + curr_pos = ftell(dvi_file); + (IGNORED) fseek(dvi_file, 0, SEEK_END); + file_len = ftell(dvi_file); + (IGNORED) fseek(dvi_file, curr_pos, `<abs file addr`>); + if( (file_len % 4) != 0 ) bad_dvi; +} +>>> + +% SEEK_SET); + + To the best of my nowledge, this works exactly like your code (I +tested it). My executable is compiled with this code. + + + +see also fgetpos and fsetpos. + +\Section{Coding Hints} +\ifHtml[\HPage{ini (initialization) files in windows}\Verbatim + +\Verbatim +/*************** foo.c file *******************/ + +#include<stdio.h> +#include<string.h> +#include<conio.h> +#include<windows.h> + + +// Windows-specific functions used: +// _fullpath : make filename into full path +// _splitpath : split a _fullpath into its component parts +// GetPrivateProfileString: handle the .ini file + +_fullpath(path,argv[0],250); +_splitpath(path,drive,dir,filname,ext); + +char TEXINAME[100], NOBATCHNAME[MV2]; + +GetPrivateProfileString("Files", "TEXINAME", NOBATCHNAME, TEXINAME, 100, "foo.ini"); +GetPrivateProfileString("Strings", "SWPPACK", dSWPPACK, SWPPACK, 100,"foo.ini"); +DEBFLAG=GetPrivateProfileInt("integers", "DEBFLAG",0, "foo.ini"); + +/*************** foo.ini file ********************/ + +[integers] +; DEBFLAG = 1 prints additional details +DEBFLAG = 0 + +[files] +; texinfo +TexiName = texis.bat + +[strings] +; swp package +SWPPACK = {swpht} + +\EndVerbatim\EndHPage{}]\fi + +\ifHtml[\HPage{detecting tex tree}\Verbatim + > > on a Windows machine? (How can the installer know where to put files + > > without actually searching the entire hard disc.) Any ideas? + > + > Unfortunately, I have no idea on how to avoid a global search. + +a) create a file foo.tex containing + hello + \bye +b) run + tex foo.tex +c) open foo.log and analyze the results. you should be able to get all +the clues you need about their setup + +\EndVerbatim\EndHPage{}]\fi + + + +\ifHtml[\HPage{kpathsea}\Verbatim +My key discovery was the library `kpathsea' which does file name look up. +And in particular `kpsewhich --show-path TEXFILETYPE'. So, for example, +`kpsewhich --show-path tfm' returns a colon separated list of paths to tfm +files. + +\EndVerbatim\EndHPage{}]\fi + +\ifHtml[\HPage{more}\Verbatim +with some help from my neighbour, i got this working at last.... + +you had + + if( *(p = gif_open[gif_flag]) ) IGNORED) strct(str,p); + +which we changed to + + p = gif_open[gif_flag]; + if( p && *p) (IGNORED) strct(str,p); + +because if gif_open[fig_flag] is NULL (which you initialize it to +be!), then the *p points to a dead end..... + + +this applied in some other places too, see appended diff. + + { struct group_info *p, *last; + p = stack[ stack_n ].begin; +\EndVerbatim\EndHPage{}]\fi + + +\Chapter{Structure of Dvi Files} + +\Section{Background} +\Link[http://www.rpi.edu/\string~sofkam/DVI/dvi.html]{}{}DVI driver standards \EndLink + + +Dvi files are consisted of three parts. + + +\bgroup +\def\.#1.#2.{% + \ifcase #1 + \Link{#2}{dvistrct}\or + \Link{#2}{}\or + \Link{#2}{}\fi + #2\EndLink} +\Verbatim-\ ++-----------+ +| \.0.preamble. | ++-----------+ +| \.1.pages. | ++-----------+ +| \.2.postamble. | ++-----------+ +\EndVerbatim +\egroup + + +\SubSection{Example} + +\Link{}{dvcd} \EndLink{} + +\Verbatim +000000: PRE version : 2 +000002: numerator : 25400000 +000006: denominator : 473628672 +000010: magnification : 1000 +000014: job name ( 27) : TeX output 1995.02.22:0104 +000042: BOP page number : 1 +000047: 0 0 0 +000059: 0 0 0 +000071: 0 0 0 +000083: prev page offset : -00001 +000087: PUSH +000088: DOWN3: -917504 +000092: POP +000093: DOWN4: 42152922 +000098: PUSH +000099: DOWN4: -41497562 +000104: PUSH +000105: FNT_DEF1: 29 +000107: checksum : -538297224 +000111: scale : 655360 +000115: design : 655360 +000119: name : cmtt10 +000127: FONT_29 +000128: Char: <HTML><TITLE>try.htex</TITLE><BODY> +000163: POP +000164: Y3: 786432 +000168: PUSH +000169: PUSH +000170: RIGHT3: 1310720 +000174: Char: <P> +000177: POP +000178: RIGHT3: 2342903 +000182: FNT_DEF1: 12 +000184: checksum : 555887770 +000188: scale : 655360 +000192: design : 655360 +000196: name : cmsy10 +000204: FONT_12 +000205: Char: ff /* ligature (non-printing) */ +000206: W3: 145632 +000210: Char: 0x 0 +000211: W0 +000212: Char: A +000213: PUSH +000214: DOWN3: -237825 +000218: Char: ffi /* ligature (non-printing) */ +000219: POP +000220: RIGHT3: 704510 +000224: FONT_29 +000225: Char: A +000226: RIGHT3: 344061 +000230: Char: B +000231: POP +000232: Y0 +000233: PUSH +000234: Char: </BODY></HTML> +000248: POP +000249: POP +000250: DOWN3: 1572864 +000254: EOP +000255: POST last page offset : 000042 +000260: numerator : 25400000 +000264: denominator : 473628672 +000268: magnification : 1000 +000272: max page height : 43725786 +000276: max page width : 30785863 +000280: stack size needed: 3 +000282: number of pages : 1 +000284: FNT_DEF1: 29 +000286: checksum : -538297224 +000290: scale : 655360 +000294: design : 655360 +000298: name : cmtt10 +000306: FNT_DEF1: 12 +000308: checksum : 555887770 +000312: scale : 655360 +000316: design : 655360 +000320: name : cmsy10 +000328: POSTPOST postamble offset : 000255 +000333: version : 2 +000334: TRAILER +000335: TRAILER +000336: TRAILER +000337: TRAILER +000338: TRAILER +000339: TRAILER +\EndVerbatim + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Scan Postamble} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +The postamble of a \Link{dvistrct}{postamble}dvi file\EndLink{} has the +following structure. It should be consistent with the preamble. + +\bgroup +\def\.#1.{\Link{fntdef}{}#1\EndLink} +\Verbatim-\ +no_ops ??? >= 0 bytes NOPS, I think they are allowed here... +postamble_marker 1 ubyte POST +last_page_offset 4 sbytes +numerator 4 ubytes +denominator 4 ubytes +magnification 4 ubytes +max_page_height 4 ubytes +max_page_width 4 ubytes +max_stack 2 ubytes +total_pages 2 ubytes number of pages in file +... \.FONT DEFINITIONS. ... +POST_POST 1 byte +postamble_offset 4 sbytes offset in file where postamble starts +version_id 1 ubyte +trailer >= 4 ubytes TRAILER +<EOF> +\EndVerbatim +\egroup + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{No Op's at the End of File} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Verify \LinkPort\<eof op\>{}eof op\EndLink{} and version number + at postamble. There should be at least four trailing characters, and + normally there are no more than seven. They act as signatyre and + provide for file lengths that are divisible by four, aimed at + machines that pack four bytes into a word. + +\<scan postamble\><<< +i=0; +do{ + i++; file_len -= 1; + (IGNORED) fseek(dvi_file, file_len, `<abs file addr`>); +} while( (ch=get_char()) == `<eof op`> ); +eof_op_n = file_len; +if( (i<4) + || + ((ch != `<version dvi`>) && (ch > `<version xdv`>)) + ) bad_dvi; +version_id = ch; +>>> + + + +\<vars\><<< +static int version_id; +>>> + + + +The function \`'(IGNORED) fseek' enables random access to file. + +\<abs file addr\><<< +0>>> + +\<relative file addr\><<< +1>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Find Start of Postamble} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<scan postamble\><<< +file_len -= 5; +(IGNORED) fseek(dvi_file, file_len, `<abs file addr`>); +if( get_char() != `<end-postamble op`> ) bad_dvi; +eof_op_n -= begin_postamble = get_unt(4); +(IGNORED) fseek(dvi_file, begin_postamble, `<abs file addr`>); +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Find Stack Size and Number of Pages} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<scan postamble\><<< +if( get_char() != `<begin-postamble op`> ) bad_dvi; +(IGNORED) fseek(dvi_file, 16L, `<relative file addr`>); +`<max page dimensions`> +if( (stack_len = (int) get_unt(2)) < 1) bad_dvi; +`<stack = m-alloc...`> +unread_pages = (int) get_unt(2); +>>> + + + +\<main's vars\><<< +int unread_pages; +>>> + + +\<vars\><<< +static int stack_len; +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Font Definitions} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<scan postamble\><<< +{ `<scan fonts vars`> + BOOL missing_fonts; +#ifndef KPATHSEA + `<fls var`> + `<get dir of tex4ht.fls`> + `<open old cache file`> +#endif + `<init scan fonts vars`> + missing_fonts = FALSE; + `<check env font variables`> + `<start loading fonts`> + `<load unicode.4hf`> + while( (ch = get_char()) != `<end-postamble op`> ){ + `<scan font entry`> + } + `<end loading fonts`> + if( missing_fonts ) err_i(14); +#ifndef KPATHSEA + `<close old cache file`> + `<set new cache file`> +#endif + `<free html font memory`> +} +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Scan Preamble} +%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +The preamble of a \Link{dvistrct}{preamble}dvi file\EndLink{} has the +following structure. + +\Verbatim +no_ops >= 0 bytes NOP, nops before the preamble +preamble_marker 1 ubyte PRE +version_id 1 ubyte +numerator 4 ubytes +denominator 4 ubytes +magnification 4 ubytes +id_len 1 ubyte lenght of identification string +id_string id_len ubytes identification string +\EndVerbatim + + + +\<scan preamble\><<< +(IGNORED) fseek(dvi_file, 0L, `<abs file addr`>); +ch = get_noop(); +if( ch != `<start of preamble op`> ) bad_dvi; +if( ((int) get_char()) != version_id ) bad_dvi; +(void) get_unt(4); `%numerator = (INTEGER) get_unt(4);`% +(void) get_unt(4); `%denominator = (INTEGER) get_unt(4);`% +`%magnification =`% (void) get_unt(4); +for( i= get_char(); i>0; i-- ) ch = get_char(); +>>> + + + + + +\<version dvi\><<< +2 >>> + + +The following is from xetex. As of XeTeX 3.14159265-2.6-0.99996 (TeX +Live 2016), the id value is 7, but it seems prudent and harmless to +allow for a few future updates without recompiling. Or perhaps we +should not check this value at all with xdv. + +\<version xdv\><<< +10 +>>> + + +%%%%%%%%%%%%%%%%%%%% +\Section{Scan Pages} +%%%%%%%%%%%%%%%%%% + +The pages in a \Link{dvistrct}{pages}dvi file\EndLink{} have the +following structure. + + +\Verbatim +no_ops >= 0 bytes NOP +begin_of_page 1 ubyte BOP +page_nr 4 sbytes page number + 36 bytes +prev_page_offset 4 sbytes offset in file where previous + page starts, -1 for none +... PAGE DATA ... +end_of_page 1 ubyte EOP +\EndVerbatim + + + +\<scan pages\><<< +{ + dis_pages = unread_pages; + while( unread_pages-- ){ + (IGNORED) printf("[%d", dis_pages - unread_pages); + `<initial values for new page`> + if( get_noop() != `<start page op`> ) bad_dvi; + for( i = 1; i<45; i++ ) + if( get_char() == EOF ) bad_dvi; + while( (ch = get_char()) != `<end page op`> ){ + `<process ch according to the case`> + } + `<dump ch-map at end of page`> + (IGNORED) printf("]%c",unread_pages % 10 == 0? '\n' : ' '); + put_char('\n'); +} } +>>> + + +The new line at end of pages is importnant and problematic for +verbatim environment that are expressed by \`'<pre>' elements + + + + +\<initial values for new page\><<< +x_val = dx_1 = dx_2 = 0; max_x_val = -10000; `%temp`% +y_val = max_y_val = prev_y_val = dy_1 = dy_2 = 0; +>>> + +[\Link{dvcd}{}example of a dvi file\EndLink] + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Dvi Trace} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +Good for post processing by plug-ins of `tex4ht.c'. That is, we set +\ifHtml[\HPage{hints}\Verbatim +Date: Fri, 22 Aug 1997 20:50:03 -0400 (EDT) +From: Eitan Gurari <gurari@cse.ohio-state.edu> +To: ... +Subject: LaTeX (TeX?) to MathML converter + + +The way that I understand it, the current proposal is to build a new +engine for math formulas, modeled after the one used by TeX. It seems +to me that, with a little change of a direction, we might have here a +golden opportunity to get much more than just a converter to MathML +from a subset of (La)TeX. + +The alternative approach I have in mind consists of a minor +modification to the TeX engine, for optionally seeding dvi files with +\special-hints. Specifically, in standard mode, TeX will output the +standard dvi output, and ignore the modifications made to its +engine. On the other hand, in `special' mode (activated, e.g., by a +switch in a command line), TeX will output self-created \special +instructions into the dvi code. + +The specials will mark strategic points in the dvi code, with the +objective of acting as hints to drivers which process the dvi code. +In the case of formulas, the hints will identify the boundaries of the +formulas, the subscripts and superscripts, and other entities of +significance. In the case of halign and valign tables, the specials +will be placed around the tables, around the rows, around the entries, +and at omitted boundaries. Other locations of possible interest might +be page, paragraph, and line breaks. Hence, creating sgml-oriented +tagging, with desirable interpretations provided by dvi drivers. + +The following are the main advantages that I can see for the +alternative approach. + +1. Compatibility. The marking by the special hints will work with + all TeX-based source documents, no matter what instructions and + style files they employ (including the rich collection of amstex + and amslatex documents). + +2. Flexibility. Alternative sgml tags to MathML will be possible, + including tags customized by users with realizations in + style sheets. Non-hypertext applications might also find uses for + structural hints emitted by TeX. + +3. Usability. The original proposal is oriented toward + latex2html like systems that try to emulate, only with partial + success, the behavior of TeX. The alternative proposal will serve + such systems, as well as more recent systems that rely on the + native engine of TeX to do the job (e.g., vtex, tex4ht--my system). + + In fact, latex2html will need to do only a minor adjustment + to its current implementation. Instead of placing <IMG> pointers to + gif's created externally for the figures, it will import + the MathML code created externally. + +4. Portability. The same as for TeX. + +5. Effort. It seems to me that the effort needed to modify the + TeX program should be minimal, for someone who is familiar with + the program (not me). I guess the following statement + from the TeX program is applicable here. + + 1340. Extensions. The program above includes a bunch of "hooks" that + allow further capabilities to be added without upsetting TeX's basic + structure. Most of these hooks are concerned with "whatsit" nodes, + which are intended to be used for special purposes; whenever a new + extension to TeX involves a new kind of whatsit node, a corresponding + change needs to be made to the routines below that deal with such + nodes, but it will usually be unnecessary to make many changes to the + other parts of this program. + + In order to demonstrate how extensions can be made, we shall treat + `\write', `\openout', `\closeout', `\immediate', `\special', and + + Extracting the code from the dvi files should be a straightforward + task for a driver, when the special hints are present. + + On the other hand, the following quote from the TeX program might + also be of interest, if the original proposal intends to include tables. + + 768. Alignment. It's sort of a miracle whenever \halign and \valign + work, because they cut across so many of the control structures of + TeX. + +6. Stability. The core of the TeX engine is a frozen component, probably + untouched even by its recent extensions (etex, pdftex, ...). Hence, a + well thought set of \special-hints will provide a stable base for + different drivers to play with. + +Thanks for your attention, -eitan + + +> Consultant/Programmer sought to develop an LaTeX to MathML converter: +> +<snip> +> +> The MathML specificaion was written with an eye toward the ability to +> convert other mathematical data formats into MathML. Translators that +> can convert mathematical documents utilizing TeX markup will be +> especially useful due to the large quantity of TeX documents that the +> research mathematics community has authored over the past decade. +> +> The AMS, the Geometry Center, and SIAM intend to collaborate to +> support the development of a general purpose LaTeX to MathML +> translator, using the popular public-domain LaTeX2HTML utility as +> model. LaTeX2HTML converts a LaTeX document into an HTML document in +> two general passes. First, LaTeX document structures are converted +> into HTML (e.g. \section to <H1>) and second, each piece of LaTeX math +> is converted into a GIF graphic and inserted into the HTML document +> with an <IMG> command. +> +> We are seeking a consultant/programmer skilled in both TeX and Perl +> (LaTeX2HTML is written in Perl) to adapt LaTeX2HTML to create MathML +> code for each piece of LaTeX math rather than producing GIF graphics. +> Since the end result must be completely compatible with LaTeX, we are +> envisioning the job in terms of modifying TeX to convert its internal +> math list structures into MathML. However, the exact methodology +> employed would be at the discretion of the consultant. +> +<snip> + + + + +\EndVerbatim\EndHPage{}]\fi{} +for the postprocessors. + + +\List{disc} +\item \`'@%P' --- On-off modes for traceing of POP, PUSH in DVI +\item \`'@%C' --- On-off modes for traceing CHAR...RAHC in DVI +\item \`'@%H' --- On-off modes for traceing h spaces +\item \`'@%V' --- On-off modes for traceing v spaces +\item \`'@%R' --- On-off modes for traceing x rulers + + +In all the above, uppercase for plus, lowercase for minus 1 + +\item \`'@%%Zx...pre...x...post...' --- Group tracing. + Default \`'<!-- DVI ' and \`'\n-->', where \''\n' represents + new line char (i.e., \`'\EolnCh'). + \`'x' can be any character. if it is not there, + the postfix is assumed to be empty. + +Z: P, p, D, d,.... + +\item \`'@%...' --- Not used, if not of the above format +\EndList + + + + +\<dvi trace\><<< +if( special_n>1 ) { + special_n--; + if ( get_char() == '%' ) { + if( special_n>2 ) { `<delimiters for trace dvi`> } + else { `<consume unused specials`> } + } else { `<consume unused specials`> } +} else if( special_n ) { + special_n--; + switch ( get_char() ){ + case 'P': { trace_dvi_P++; break; } + case 'C': { trace_dvi_C++; break; } + case 'V': { trace_dvi_V++; break; } + case 'H': { trace_dvi_H++; break; } + case 'R': { trace_dvi_R++; break; } + case 'p': { trace_dvi_P--; break; } + case 'c': { trace_dvi_C--; break; } + case 'v': { trace_dvi_V--; break; } + case 'h': { trace_dvi_H--; break; } + case 'r': { trace_dvi_R--; break; } + default: { ; } +} } +>>> + +Options 'h' and 'v' are not in use. + + + + + + + +\<css for chars\><<< +if( span_on && (default_font != font_tbl[cur_fnt].num) ){ + if( !ch_map_flag && start_span ){ + if( span_name_on ){ + `<open output file`> + if( span_open[0] ) if( *span_open[0] ) + (IGNORED) fprintf(cur_o_file, "%s", span_open[0]); + if( span_name[0] ) if( *span_name[0] ) + (IGNORED) fprintf(cur_o_file, + span_name[0], font_tbl[cur_fnt].family_name); + if( span_size[0] ) if( *span_size[0] ) + (IGNORED) fprintf(cur_o_file, + span_size[0], font_tbl[cur_fnt].font_size); + if( span_mag[0] ) + if( *span_mag[0] && (font_tbl[cur_fnt].mag != 100)) + (IGNORED) fprintf(cur_o_file, + span_mag[0], font_tbl[cur_fnt].mag); + if( span_ch[0] ) if( *span_ch[0] ) + (IGNORED) fprintf(cur_o_file, "%s", span_ch[0]); + } + start_span = FALSE; + } +} +>>> + +% `<...gif font mag...`> + + + + + + + + + + + + +\<vars\><<< +static BOOL start_span = FALSE, in_span_ch = FALSE; +>>> + + + +\<span char block\><<< +if( span_on && !in_span_ch && !ignore_chs && !in_accenting + && (default_font != font_tbl[cur_fnt].num) ){ + if( (ch < 137) && (ch != `<insert rule + move op`>) ){ + in_span_ch = TRUE; start_span = TRUE; +} } +else if ( in_span_ch ){ + if( !span_on || + (ch == `<insert rule + move op`>) || + ((136 < ch) && (ch < `<mv hor 1-byte`>)) || + (ch > `<dx.2 store and mv hor 4-byte`>) + ){ + in_span_ch = FALSE; + if( *end_span[0] ){ + `<open output file`> + (IGNORED) fprintf(cur_o_file, "%s", end_span[0]); + } +} } +>>> + + + +\<end accented span\><<< +if( span_on && in_span_ch ){ + if( *end_span[0] ){ + in_span_ch = FALSE; + `<open output file`> + (IGNORED) fprintf(cur_o_file, "%s", end_span[0]); +} } +>>> + + +\<end css for chars\><<< + +>>> + + + + +\<trace dvi char block\><<< +if( trace_dvi_C && !in_trace_char ){ + if( (ch < 137) && (ch != `<insert rule + move op`>) ){ + in_trace_char = TRUE; block_start = TRUE; +} } +else if ( in_trace_char ){ + if( !trace_dvi_C || (ch > 136) || (ch == `<insert rule + move op`>) ){ + in_trace_char = FALSE; +} } +>>> + + + + + + +\SubSection{Setting the Delimiters} + +The special is assumed to offer a pattern of the form \`'type-ch +del-ch ..... del-ch ....'. + + +\<delimiters for trace dvi\><<< + U_CHAR type, ch, *p, *q, *pp=0, *qq=0, pre[256], post[256]; +special_n -= 2; type = get_char(); ch = get_char(); +p = pre; +while( special_n-- > 0 ) { + if ( (*(p++)=get_char() ) == ch ) { p--; break; } +} +*p = '\0'; +p = post; +while( special_n-- > 0 ) { *(p++)=get_char(); } *p='\0'; +>>> + + +\<delimiters for trace dvi\><<< +p = m_alloc(char, 1 + (int) strlen((char *) pre)); +(IGNORED) strcpy((char *) p, (char *) pre ); +q = m_alloc(char, 1 + (int) strlen((char *) post)); +(IGNORED) strcpy((char *) q, (char *) post ); +>>> + + + +\<delimiters for trace dvi\><<< +switch ( type ){ + case 'P': { + pp = trace_dvi_del_P; trace_dvi_del_P = p; + qq = end_trace_dvi_del_P; end_trace_dvi_del_P = q; + break; } + case 'C': { + pp = trace_dvi_del_C; trace_dvi_del_C = p; + qq = end_trace_dvi_del_C; end_trace_dvi_del_C = q; + break; } + case 'V': { + pp = trace_dvi_del_V; trace_dvi_del_V = p; + qq = end_trace_dvi_del_V; end_trace_dvi_del_V = q; + break; } + case 'H': { + pp = trace_dvi_del_H; trace_dvi_del_H = p; + qq = end_trace_dvi_del_H; end_trace_dvi_del_H = q; + break; } + case 'R': { + pp = trace_dvi_del_R; trace_dvi_del_R = p; + qq = end_trace_dvi_del_R; end_trace_dvi_del_R = q; + break; } + case 'p': { + pp = trace_dvi_del_p; trace_dvi_del_p = p; + qq = end_trace_dvi_del_p; end_trace_dvi_del_p = q; + break; } + case 'c': { + pp = trace_dvi_del_c; trace_dvi_del_c = p; + qq = end_trace_dvi_del_c; end_trace_dvi_del_c = q; + break; } + case 'v': { + pp = trace_dvi_del_v; trace_dvi_del_v = p; + qq = end_trace_dvi_del_v; end_trace_dvi_del_v = q; + break; } + case 'h': { + pp = trace_dvi_del_h; trace_dvi_del_h = p; + qq = end_trace_dvi_del_h; end_trace_dvi_del_h = q; + break; } + case 'r': { + pp = trace_dvi_del_r; trace_dvi_del_r = p; + qq = end_trace_dvi_del_r; end_trace_dvi_del_r = q; + break; } + default: { ; } +} +free((void *) pp); +free((void *) qq); +>>> + + + + + + + + + +\<vars\><<< +static BOOL in_trace_char = FALSE, block_start = FALSE; +static int trace_dvi_P = 0, trace_dvi_C = 0, + trace_dvi_H = 0, trace_dvi_R = 0, trace_dvi_V = 0; +static U_CHAR *trace_dvi_del_P, *end_trace_dvi_del_P, + *trace_dvi_del_p, *end_trace_dvi_del_p, + *trace_dvi_del_C, *end_trace_dvi_del_C, + *trace_dvi_del_c, *end_trace_dvi_del_c, + *trace_dvi_del_H, *end_trace_dvi_del_H, + *trace_dvi_del_h, *end_trace_dvi_del_h, + *trace_dvi_del_R, *end_trace_dvi_del_R, + *trace_dvi_del_r, *end_trace_dvi_del_r, + *trace_dvi_del_V, *end_trace_dvi_del_V, + *trace_dvi_del_v, *end_trace_dvi_del_v; +static int push_depth=0, push_id=0, push_st[256]; +>>> + + + + + + + + + + + +\<cmd line trace groups\><<< +trace_dvi_P++; +if( !( *trace_dvi_del_P || *end_trace_dvi_del_P + || *trace_dvi_del_p || *end_trace_dvi_del_p + ) + ){ + trace_dvi_del_P = + (char *) r_alloc((void *) trace_dvi_del_P, + (size_t) 4); + (IGNORED) strcpy((char *) trace_dvi_del_P, "[G " ); + end_trace_dvi_del_P = + (char *) r_alloc((void *) end_trace_dvi_del_P, + (size_t) 2); + (IGNORED) strcpy((char *) end_trace_dvi_del_P, "]" ); + trace_dvi_del_p = + (char *) r_alloc((void *) trace_dvi_del_p, + (size_t) 5); + (IGNORED) strcpy((char *) trace_dvi_del_p, "[/G " ); + end_trace_dvi_del_p = + (char *) r_alloc((void *) end_trace_dvi_del_p, + (size_t) 2); + (IGNORED) strcpy((char *) end_trace_dvi_del_p, "]" ); +} +>>> + + + + +\<init traces\><<< +set_del( &trace_dvi_del_P, &end_trace_dvi_del_P); +set_del( &trace_dvi_del_p, &end_trace_dvi_del_p); +set_del( &trace_dvi_del_C, &end_trace_dvi_del_C); +set_del( &trace_dvi_del_c, &end_trace_dvi_del_c); +set_del( &trace_dvi_del_H, &end_trace_dvi_del_H); +set_del( &trace_dvi_del_h, &end_trace_dvi_del_h); +set_del( &trace_dvi_del_R, &end_trace_dvi_del_R); +set_del( &trace_dvi_del_r, &end_trace_dvi_del_r); +set_del( &trace_dvi_del_V, &end_trace_dvi_del_V); +set_del( &trace_dvi_del_v, &end_trace_dvi_del_v); +>>> + + + + + +\<header functions\><<< +static void set_del( ARG_II(char **, U_CHAR **) ); +>>> + +\<functions\><<< +`[ +static void set_del( del, end_del ) + U_CHAR ** del`; + U_CHAR ** end_del +;{ + *del = m_alloc(char, 1); **del = '\0'; + *end_del = m_alloc(char, 1); **end_del = '\0'; +} +>>> + + + + + + +\SubSection{Using the Delimiters} + + + +\<trace h spaces\><<< +if( trace_dvi_H && !ch_map_flag ){ + if( *trace_dvi_del_H != '\0' ){ + (IGNORED) fprintf(cur_o_file, "%s%d", trace_dvi_del_H, (int) dx); + } + (IGNORED) fprintf(cur_o_file, "%s", end_trace_dvi_del_H); +} +>>> + +\<trace v spaces\><<< +if( trace_dvi_V && !ch_map_flag ){ + if( *trace_dvi_del_V != '\0' ){ + (IGNORED) fprintf(cur_o_file, "%s%d", trace_dvi_del_V, d); + } + (IGNORED) fprintf(cur_o_file, "%s", end_trace_dvi_del_V); +} +>>> + + + + + +\<trace x rules\><<< +if( trace_dvi_R && !ch_map_flag ){ + if( *trace_dvi_del_R != '\0' ){ + (IGNORED) fprintf(cur_o_file, "%s%d %d", + trace_dvi_del_R, (int) x_val, (int) y_val); + } + (IGNORED) fprintf(cur_o_file, "%s", end_trace_dvi_del_R); +} +>>> + + +\<end trace x rules\><<< +if( trace_dvi_R && !ch_map_flag ){ + if( *trace_dvi_del_r != '\0' ){ + (IGNORED) fprintf(cur_o_file, "%s%d %d", + trace_dvi_del_R, (int) right, (int) up); + } + (IGNORED) fprintf(cur_o_file, "%s", end_trace_dvi_del_r); +} +>>> + + + +\<trace dvi push\><<< +if( push_depth<256 ) { push_st[push_depth] = push_id++; } +if( trace_dvi_P && !ch_map_flag ){ + `<open output file`> + if( *trace_dvi_del_P != '\0' ){ + (IGNORED) fprintf(cur_o_file, "%s%d %d", + trace_dvi_del_P, push_depth, + push_st[(push_depth<256)? push_depth:256]); + } + (IGNORED) fprintf(cur_o_file, "%s", end_trace_dvi_del_P); +} +push_depth++; +>>> + + + +\<trace dvi pop\><<< +push_depth--; +if( trace_dvi_P && !ch_map_flag ){ + `<open output file`> + if( *trace_dvi_del_p != '\0' ){ + (IGNORED) fprintf(cur_o_file, "%s%d %d", + trace_dvi_del_p, push_depth, + push_st[(push_depth<256)? push_depth:256]); + } + (IGNORED) fprintf(cur_o_file, "%s", end_trace_dvi_del_p); +} +>>> + + +\<trace dvi char\><<< +if( trace_dvi_C ){ + if( !ch_map_flag ){ + `<open output file`> + if( *trace_dvi_del_C != '\0' ){ + (IGNORED) fprintf(cur_o_file, + block_start? "%s%s %d B" : "%s%s %d", + trace_dvi_del_C, font_tbl[cur_fnt].name, ch); + } + (IGNORED) fprintf(cur_o_file,"%s", end_trace_dvi_del_C); + } + block_start = FALSE; +} +>>> + + +\<end trace dvi char\><<< +if( trace_dvi_C && !ch_map_flag ){ + `<open output file`> + (IGNORED) fprintf(cur_o_file, "%s%s", + trace_dvi_del_c, end_trace_dvi_del_c); +} +>>> + + + +\Chapter{Semantics of Dvi Code} + +[\Link{dvcd}{}example of a dvi file\EndLink] + + +\Section{Scanning the Characters} + +\<process ch according to the case\><<< +{ register int ch_1; + ch_1 = ch; + `<auto quit halign`> + `<process indirect character ch`> + `<get back sub/sup before ch`> + `<trace dvi char block`> + `<span char block`> + `<pre accent symbol`> + if( ch < 132 ) { + x_val += math_class_on? `<set-ch-class(ch-1)`> + : insert_ch(ch_1); `%typset and move`% + if( max_x_val < x_val ) max_x_val = x_val; + } else switch( ch ) { + case 133: case 134: case 135: case 136: {`%typset and don't move`% + INTEGER w; + w = math_class_on? `<set-ch-class(ch-1)`> : insert_ch(ch_1); + max_x_val = ( x_val + w > max_x_val )? x_val + w : max_x_val; + break; + } + `<process dvi op 'ch'`> + } +} +>>> + +Characters are inserted into the html file as they are +encountered. Spaces are inserted when \`'x_val' is larger than +\`'max_x_val'. + +\<vars\><<< +static long int x_val = 0, max_x_val = -10000, + max_y_val = 0, prev_y_val = 0; +>>> + + + + +\Section{Spaces} + + + + + + + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Line Breaks} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + + +Conditionally start new line. + +\<header functions\><<< +static void try_new_line( ARG_I(void) ); +>>> + +\<functions\><<< +static void try_new_line(MYVOID) +{ long int v; + double dy; + dy = (cur_fnt == -1)? 0.0 : (`<sign of ex`> * `<size of ex`>) ; + v = y_val - prev_y_val; + if( !text_on && (y_val > max_y_val) ){ + if( v > dy/2.5 ){ + `<cond insert new line`> max_x_val = -10000; + prev_y_val = max_y_val = stack_n? y_val : 0; + } + }else{ + if( v > dy ){ `<cond insert new line`> max_x_val = x_val; + prev_y_val = stack_n? y_val : 0; + }else if( v < -(dy / 1.4) ) prev_y_val = stack_n? y_val : 0; +} } +>>> + +The 2.5 divisor provide a line break before b, but not before 5 and a +in \'+${A'}_{5_{a_b}}$+. + + + +\<sign of ex\><<< +(`<size of ex`> < 0? -1 : 1) +>>> + +\`+<size of ex>+ is negative in hclassic font of hebrew, and probably also in +other right-to-left fonts. + + +In default font, one ex is about 4.5pt. We take distances greatr than +1.7ex for distance between lines and distances smaller than of +(1.7/1.3)ex from base line to superscript. My TeX inserts superscripts +before subscripts into the dvi files, no matter what order they have +in the input (otherwise, TeX obeys the input order in the output). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Move Horizontally} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<process dvi op 'ch'\><<< +case `<mv hor 1-byte`>: {;} +case `<mv hor 2-byte`>: {;} +case `<mv hor 3-byte`>: {;} +case `<mv hor 4-byte`>: { + try_new_line(); + (void) move_x((INTEGER) get_int(ch - `<mv hor 1-byte`> + 1 )); + break; } +>>> + +\<process dvi op 'ch'\><<< +case `<mv hor dist dx.1`>: { + (void) move_x( dx_1 ); break; } +case `<dx.1 store and mv hor 1-byte`>: {;} +case `<dx.1 store and mv hor 2-byte`>: {;} +case `<dx.1 store and mv hor 3-byte`>: {;} +case `<dx.1 store and mv hor 4-byte`>: { + try_new_line(); + dx_1 = move_x((INTEGER) get_int(ch - `<mv hor dist dx.1`> )); + break; } +>>> + +\<process dvi op 'ch'\><<< +case `<mv hor dist dx.2`>: { + (void) move_x( dx_2 ); break; } +case `<dx.2 store and mv hor 1-byte`>: {;} +case `<dx.2 store and mv hor 2-byte`>: {;} +case `<dx.2 store and mv hor 3-byte`>: {;} +case `<dx.2 store and mv hor 4-byte`>: { + try_new_line(); + dx_2 = move_x((INTEGER) get_int(ch - `<mv hor dist dx.2`> )); + break; } +>>> + + +\<vars\><<< +static INTEGER dx_1 = 0, dx_2 = 0; +>>> + + + + +\<header functions\><<< +static INTEGER move_x( ARG_I(register INTEGER) ); +>>> + +\<functions\><<< +`[ +static INTEGER move_x( d ) + register INTEGER d +;{ register long i, dx; + x_val += d; + if( (x_val > max_x_val) && x_val ){ + if( max_x_val == -10000) max_x_val = x_val - d; + `<insert space`> + } else if( d && text_on && (x_val != max_x_val) ){ + `<space for llap`> + } + return d; +} +>>> + +\''x_val == max_x_val' typically occurs in push after +\ifHtml[\HPage{hbox}\Verbatim +\documentclass{article} + +\usepackage[html,3.2]{tex4ht} + +\begin{document} + +\parindent=0pt + +\section{foo} + +\leavevmode=1=\hbox{=2N=}=N3= %[2694266,1347133,2694266] + +\leavevmode=4N=\llap{=N5Y=} =Y6= %[983040,-1347133,2330173] + +\leavevmode=4=\llap{= 7 =} = 8 = %[983040,-1347133,2330173] + +\leavevmode\llap{= 9 = } = 0 = + +\end{document} +\EndVerbatim\EndHPage{}]\fi +to compansate for loss of space due to a pop.. + + + +The \''\llap' create problems for spaces, e.g., in section number at +section heads. The same might happen for \''\hrule'. +The following provides a solution. + +\<space for llap\><<< +if( !ignore_spaces ){ + i = (INTEGER) ( (double) (dx = d) / word_sp + 0.5 ); + if( i<0 ) i=0; + if( !i ) i = dx>99999L; + if( i ){ put_char(' '); } +} +>>> + +Originally, we had also \`'(max_x_val == -10000)' in the else part. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Move Vertically} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<process dvi op 'ch'\><<< +case `<mv ver 1-byte`>: {;} +case `<mv ver 2-byte`>: {;} +case `<mv ver 3-byte`>: {;} +case `<mv ver 4-byte`>: { + (void) move_y( (INTEGER) get_int(ch - `<mv ver 1-byte`> + 1 )); + break; } +>>> + +\<process dvi op 'ch'\><<< +case `<mv ver dist dy.1`>: { (void) move_y( dy_1 ); break; } +case `<dy.1 store and mv ver 1-byte`>: {;} +case `<dy.1 store and mv ver 2-byte`>: {;} +case `<dy.1 store and mv ver 3-byte`>: {;} +case `<dy.1 store and mv ver 4-byte`>: { + dy_1 = move_y( (INTEGER) get_int(ch - `<mv ver dist dy.1`> )); + break; } +>>> + +\<process dvi op 'ch'\><<< +case `<mv ver dist dy.2`>: { (void) move_y( dy_2 ); break; } +case `<dy.2 store and mv ver 1-byte`>: {;} +case `<dy.2 store and mv ver 2-byte`>: {;} +case `<dy.2 store and mv ver 3-byte`>: {;} +case `<dy.2 store and mv ver 4-byte`>: { + dy_2 = move_y( (INTEGER) get_int(ch - `<mv ver dist dy.2`> )); + break; } +>>> + +\<vars\><<< +static INTEGER dy_1 = 0, dy_2 = 0; +static long int y_val = 0; +>>> + +\<header functions\><<< +static INTEGER move_y( ARG_I(register INTEGER) ); +>>> + +\<functions\><<< +`[ +static INTEGER move_y( d ) register INTEGER d +;{ y_val += d; + `<trace v spaces`> + return d; +} +>>> + + + +\SubSection{Typeset Indirect Characters} + +Read the character to be typsetted, insert the character, and either +move the cursor (ops 128--131) or don't (ops 133--136). + +\<process indirect character ch\><<< +if( (ch > 127) && (ch < 137) && (ch != `<insert rule + move op`>) ){ + ch_1 = (int) get_unt( (ch - (ch>132)) % 4 +1); +} +>>> + +NOTE. Didn't take care yet of character codes beyond c[1] (e.g., unicode). + + + +\ifHtml[\HPage{more}\Verbatim + \documentclass{report} + \usepackage{t1enc} + +\input tex4ht.sty \Preamble{html} + \begin{document} +\EndPreamble + +\def\x{ ü (252) ý (253)} + +\x ======== \Picture*{} \x \EndPicture{} + +\end{document} + +\EndVerbatim\EndHPage{}]\fi + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Utilities} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +Spaces are inserted when \`'x_val' is larger than +\`'max_x_val'. + + + +\<insert space\><<< +i = (INTEGER) ( (double) (dx = x_val - max_x_val) + / (text_on? word_sp : margin_sp) + + 0.5 ); +`<try word space if i=0`> +if( i<0 ) i=0; +if( i==0 ){ `<missing space`> } +if( i ){ `<trace h spaces`> } +if( !ignore_spaces ){ + `<end text accent`> + while( i-- ) { text_on=TRUE; put_char(' '); } +} else { recover_spaces = (int) i; } +max_x_val = x_val; +>>> + +\<try word space if i=0\><<< +if( i==0 ){ + i = (INTEGER) ( (double) dx + / word_sp + + 0.5 ); +} +>>> + + + +\<recover ignored space\><<< +while( recover_spaces-- ){ text_on=TRUE; put_char(' '); } +recover_spaces = 0; +>>> + + +\<ignore spaces\><<< +ignore_spaces++; +>>> + +\<end ignore spaces\><<< +ignore_spaces--; +>>> + + + +\<unhskip vars\><<< +U_CHAR *unhskip_mark; +long retract_addr; +BOOL unhskip; +int cr_fnt, ch, unskip_depth; +>>> + + + + +In the case of unhskip we don't want to inore embedded font changes. + +\<ignore chs\><<< +if( special_n ){ + `<unhskip vars`> + cr_fnt = cur_fnt; + unskip_depth = 0; + unhskip_mark = get_str( (int) special_n ); special_n=0; + retract_addr = ftell(dvi_file); + `<conditional unhskip`> + cur_fnt = cr_fnt; + free((void *) unhskip_mark); +} else { ignore_chs++;; } +>>> + + +\<conditional unhskip\><<< +unhskip = TRUE; +while( unhskip ){ + if( (ch = get_char()) >= 128 ) { + switch( ch ){ + `<ignore font def on preview pass`> + `<ignore on preview pass`> + `<ignore indirect chars on preview pass`> + `<push/pop for unhskip`> + `<hooks for conditional unhskip`> + `<fonts and default ignored on preview pass`> + } +} } +`<scan condition`> +>>> + +\<scan condition\><<< +do{ + long int i; + char *mark; + ch = get_char(); + if( + ( ch==`<special 1`>) || ( ch==`<special 2`>) || + ( ch==`<special 3`>) || ( ch==`<special 4`>) + ) + { + if( tex4ht_special( &ch, &i ) ){ + mark = get_str( (int) i ); + if( (ch=='@') && ( *mark=='?') && eq_str(mark+1,unhskip_mark)){ + break; + } } + } + (IGNORED) fseek(dvi_file, (long) retract_addr, `<abs file addr`>); +} while(FALSE); +>>> + + + +\<ignore indirect chars on preview pass\><<< +case 128: case 129: case 130: case 131: case 133: +case 134: case 135: case 136: { + (void) get_unt( (ch-(ch>132)) % 4 +1); + break; +} +>>> + + + + + + +\<push/pop for unhskip\><<< +case `<sv loc op`>: +case `<retrieve loc op`>: { break; } +>>> + + + + + +\<hooks for conditional unhskip\><<< +case `<special 1`>: case `<special 2`>: +case `<special 3`>: case `<special 4`>: { long int i; + if( tex4ht_special( &ch, &i ) ){ char *mark; + mark = get_str( (int) i ); + if( i ){ + if( (ch=='@') && eq_str(mark+1,unhskip_mark) ){ + switch( *mark ){ + case '[': { unskip_depth++; break; } + case ']': { + unhskip = !(--unskip_depth); + break; + } + default: { ; } + } } } + }else{ `<ignore non-t4ht special`> } + break; +} +>>> + + + + + + + +\<end ignore chs\><<< +if( special_n ){ + while( special_n-- > 0 ){ (void) get_char(); } +} else { ignore_chs--; } +>>> + + +\<cond ignore chs\><<< +while( special_n-- > 0 ){ (void) get_char(); } +>>> + + +\<get eoln str\><<< +if( eoln_str ){ free((void *) eoln_str); } +if( special_n ){ + eoln_str = get_str( (int) special_n ); special_n=0; +} else { eoln_str = (char *) 0; } +>>> + +\<insert eoln ch\><<< +if( eoln_str ){ print_f(eoln_str); } +else { (IGNORED) put_4ht_ch( ch, cur_o_file ); } +recover_spaces = 0; +>>> + +\<vars\><<< +static U_CHAR *eoln_str = (char *)0; +>>> + + + + + + +\<get space str\><<< +if( space_str ){ free((void *) space_str); } +if( special_n ){ + space_str = get_str( (int) special_n ); special_n=0; +} else { space_str = (char *) 0; } +>>> + +\<insert space ch\><<< +if( space_str ){ print_f(space_str); } +else { (IGNORED) put_4ht_ch( ch, cur_o_file ); } +>>> + +\<vars\><<< +static U_CHAR *space_str = (char *)0; +>>> + + + + + + + + +\<vars\><<< +static int ignore_chs=0, ignore_spaces=0, recover_spaces=0; +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Out of Place Spaces} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<missing space\><<< + long curr_pos; + BOOL done; + int ch, cr_fnt; +curr_pos = ftell(dvi_file); +done = FALSE; +while( !done ){ + ch = get_char(); + switch( ch ){ + `<h-move get space info`> + `<h-move skip font loading`> + `<case: skip font def`> + case `<sv loc op`>: + case `<retrieve loc op`>: { break; } + default: { + if( (ch < `<font 0`>) || (ch > `<font 63`>) ){ + done = TRUE; + } else { + `<check alternative space`> +} } } } +(IGNORED) fseek(dvi_file, curr_pos, `<abs file addr`>); +>>> + + + +\<check alternative space\><<< + double word_sp; +cr_fnt = ch - `<font 0`>; +cr_fnt = search_font_tbl( cr_fnt ); +word_sp = design_size_to_pt( font_tbl[cr_fnt].word_sp ) + * (double) font_tbl[cr_fnt].scale; +i = (INTEGER) ( (double) dx + / (text_on? word_sp : margin_sp) + + 0.5 ); +`<try word space if i=0`> +if( i>0 ){ i =1; } +>>> + + + + +\<h-move get space info-WAIT\><<< +case `<font 1-byte`>: +case `<font 2-bytes`>: +case `<font 3-bytes`>: +case `<font int`>: { + INTEGER n; + int ch; + n = ch - `<font 1-byte`> + 1; + cr_fnt = (int) ((n==4)? get_int(4) : get_unt((int) n)); + cr_fnt = search_font_tbl( cr_fnt ); + break; +} +>>> + + + +Removed \`'if( !i ) i = dx>99999L;' after \`'if( i<0 ) i=0;', and +insertex \`+<missing space>+ instead. It created problems for cases +like + + +\List{*} +\item +\Verbatim +\documentclass{article} + +\begin{document} + $\mathcal{ABCDEFGHIJKLMNOPQRSTUVWXYTJZ}$ +\end{document} +\EndVerbatim + +It gives \`'dx=121058' on \`'word_sp=500255.625000'. +A 0.24 ratio with a large space. + +\item +But that is problematic for: + +\Verbatim +\documentclass{article} + +\renewcommand{\rmdefault}{ptm} +\immediate\write16{........\the\textwidth} +\setlength\textwidth{478.00812pt}% + +\begin{document} + +The first is stylistic - there is inconsistent indenting, the +constants are given non-meaningful names, and are not shared between +\texttt{func} and + +\end{document} +\EndVerbatim + + + +The end is disassebled into + +\Verbatim +006066: Y0 +006067: PUSH +006068: FNT_DEF1: 16 +006070: checksum : -538297224 +006074: scale : 655360 +006078: design : 655360 +006082: name : cmtt10 +006090: FONT_16 +006091: Char: func +006095: RIGHT3: 163840 +006099: FONT_15 +006100: Char: and +006103: POP +006104: Y0 +\EndVerbatim + +We have \`'dx=163840' with \`'word_sp=344061.25' for font 16 and +\`'word_sp=163840' fot font 15. The space of 163840 seems fitting the +font that follows. + +TeX is cheating here, it should have placed the font change before +the space. +\EndList + + + +%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Rulers} +%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<process dvi op 'ch'\><<< +case `<insert rule + move op`>: { + (void) rule_x( TRUE ); break; +} +case `<insert rule + nomove op`>: { + (void) rule_x( FALSE ); break; +} +>>> + + + + + + +\<vars\><<< +static BOOL text_on = FALSE; +>>> + +Originally, we didn't have \`'text_on' in the computation of i within +\`'rule_x' and \`'move_x'. This caused a problem in case that we have +a line of the form \`'<math stuff><regular stuff>', because changes to +the variable (WHICH VARIABLE? \''x_val'?) are lost once we get out of +the math stuff. The foollowing example had the problem also after the +introduction of \Verb+text_on+, and got fixed with the +segment \Verb+<try word space if i=0>+. + +\Verbatim +\documentclass[twocolumn]{article} + +\def\chem#1{\ensuremath {\mathrm {#1}}} +\def\un#1{\ensuremath {\unskip \,\mathrm {#1}}} + +\setlength{\textwidth}{180mm} + +\begin{document} + +The bands we have identified as linear chains come in pairs, the +states are parity doublets. The structure of the intrinsic shapes +has been discussed in many works as given in the introduction +(sect.~xx). We compare the moments of inertia of the +bands in \chem{{\HCode{}}^{14}C} with the moments of inertia of other +molecular bands in light nuclei in table~xx. The +proposed bands in \chem{{\HCode{}}^{14}C} have very large values of +$\hbar^2/2\theta\approx 120$\un{keV}, consistent with the concept +of chain states. + +\end{document} +\EndVerbatim + + + + + + + + + + + + + +\<header functions\><<< +static void rule_x( ARG_I(BOOL) ); +>>> + + +\<functions\><<< +`[ +static void rule_x( tag ) + BOOL tag +;{ long i, right, up; + up = (INTEGER) get_int(4); + right = (INTEGER) get_int(4); + if( ch_map_flag ){ `<ruler into ch map`> } + else if( pos_dvi ){ + `<pos dvi x rule`> + if( tag ) x_val += right; + } else if( (up>0) && (right>0) ) { + `<typset positive rule x`> + if( tag ) x_val += right; + } else { + `<don't typset rule x`> + if( tag ) x_val += right; +} } +>>> + + +\<vars\><<< +static U_CHAR rule_ch = '_'; +static BOOL `<radical-line-off`> = FALSE; +>>> + +\<ruler ch\><<< +if( !special_n ){ rule_ch = '\0'; } +else { while( special_n-- > 0 ){ rule_ch = get_char(); } + } +>>> + + + +\<write to lg file with loc stamp\><<< + struct files_rec *p; +while( special_n-- > 0 ) (void) putc( get_char(), log_file ); +for( p = opened_files; p != (struct files_rec*) 0; p = p->next ){ + if( p->file == cur_o_file) { + (IGNORED) fprintf(log_file, "%d %s\n", + (int) ftell(cur_o_file), p->name); + break; +} } +>>> + + + + + + + +\<typset positive rule x\><<< +if( (x_val + right) && + ( ((x_val + right) > max_x_val) + || ( !text_on && !ignore_chs ) + ) +){ + if( (max_x_val == -10000) || ((x_val + right) <= max_x_val) ) + { max_x_val = x_val; } + i = (INTEGER) ( (double) (x_val + right - max_x_val) + / (text_on? word_sp : margin_sp) + + 0.5 ); + `<try word size if i=0`> + if( i && !text_on ) try_new_line(); + `<trace x rules`> + while( i-- ) { text_on=TRUE; + if( rule_ch && !`<radical-line-off`> ){ put_char(rule_ch); } + } + `<end trace x rules`> + max_x_val = x_val + right; +} +>>> + + + + +\<try word size if i=0\><<< +if( i==0 ){ + i = (INTEGER) ( (double) (x_val + right - max_x_val) + / word_sp + + 0.5 ); +} +>>> + + + + +\<radical-line-off\><<< +rule_ch_off +>>> + + + + +\<don't typset rule x\><<< +`<trace x rules`> +`<end trace x rules`> +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Command Characters} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Fonts} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<process dvi op 'ch'\><<< +`<case: skip font def`> +>>> + + +\<case: skip font def\><<< +case `<def 4 byte font`>: (void) get_char(); +case `<def 3 byte font`>: (void) get_char(); +case `<def 2 byte font`>: (void) get_char(); +case `<def 1 byte font`>: { + for( i=0; i<14; i++ ){ ch = get_char(); } + for( i=ch + get_char(); i>0; i--) (void) get_char(); + break; +} +>>> + + +\<process dvi op 'ch'\><<< +case `<xdv-native-font-def op`>: + if( version_id == `<version xdv`> ){ + `<skip font xdv def`> + break; + } +case `<xdv-glyph-array op`>: + if( version_id == `<version xdv`> ){ + `<do glyph array`> + break; + } +case `<xdv-glyph-string op`>: + if( version_id == `<version xdv`> ){ + `<do glyph string`> + break; + } +>>> + + +\<process dvi op 'ch'\><<< +default: { + if( (ch < `<font 0`>) || (ch > `<font 63`>) ) { + bad_char(ch); + } else { cur_fnt = ch - `<font 0`>; + `<search font in font-tbl`> } + break; +} +>>> + +\<process dvi op 'ch'\><<< +case `<font 1-byte`> : +case `<font 2-bytes`>: +case `<font 3-bytes`>: +case `<font int`> : { + INTEGER n; + n = ch - `<font 1-byte`> + 1; + cur_fnt = (int) ((n==4)? get_int(4) : get_unt((int) n)); + `<search font in font-tbl`> + break; } +>>> + + + +\<vars\><<< +static int cur_fnt = -1; `% should be INTEGER for DOS`% +>>> + + + + + + + + + + + + + + +\Section{Specials: Extensions to dvi Primitives} + + + + +\<process dvi op 'ch'\><<< +case `<special 1`>: {;} +case `<special 2`>: {;} +case `<special 3`>: {;} +case `<special 4`>: { `<process the specials`> break; } +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Chapter{Specials of TeX4ht} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{The Options} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<process the specials\><<< +long int special_n; + `<end text accent`> + if( tex4ht_special( &ch, &special_n) ) { int sv; sv = ch; + special_on = TRUE; `<process tex4ht special`> special_on = FALSE; + `<check for extra special chars`> + } else { `<non-t4ht special`> } +>>> + + + + + + +\<non-t4ht special\><<< +while( special_n-- ) (void) get_char(); +>>> + + + +\<header functions\><<< +static BOOL tex4ht_special( ARG_II( int*, long int*) ); +>>> + +\<functions\><<< +`[ +static BOOL tex4ht_special( chr, special_n) + int *chr`; + long int *special_n + +;{ BOOL tex4ht; + int i; + long unsigned N; + tex4ht = FALSE; + `<get special length`> + if( *special_n > (long int) 4 ){ + for(i=4; i<9; i++) special_hd[i]=get_char(); + special_hd[9]='\0'; + `<t4ht special?`> + *chr = special_hd[8]; + tex4ht = tex4ht && ( (*chr == '=') || (*chr == '<') || + (*chr == '>') || (*chr == '*') || (*chr == '@') || + (*chr == ':') || (*chr == '"') || (*chr == '~') || + (*chr == ';') || (*chr == '.') || (*chr == '^') || + (*chr == '|') || (*chr == '+') || (*chr == '!') ); + *special_n -= 5; } + else{ special_hd[4]='\0'; } + return tex4ht; +} +>>> + +We want to allow both for \`'\special{t4ht...}' and +\`'\special{T4HT...}', for cases that the \''\special' is within +\''\uppercase' (e.g., \`' +\def~{\special{t4ht=+}} +\edef\x{\uppercase{a~b}}\x +\uppercase{a~b}'). We end up with all combinations of upper and +lower case. ELIMINTE/HANDLE also all possible \''\special''s with +letters after the first four!!!!!!!!! + + +\<t4ht special?\><<< +tex4ht = (special_hd[4] == 't') || (special_hd[4] == 'T'); +tex4ht = tex4ht && special_hd[5] == '4'; +tex4ht = tex4ht && ((special_hd[6] == 'h') || (special_hd[6] == 'H')); +tex4ht = tex4ht && ((special_hd[7] == 't') || (special_hd[7] == 'T')); +if( tex4ht && trace_special ){ + `<trace specials`> +} +>>> + + + +\<get special length\><<< +*special_n = (long int) (N = get_unt(*chr - `<special 1`> + 1)); +for(i=4; i--; ){ + special_hd[i] = (unsigned char) (N & 0xFF); + N = N >> 8; } +>>> + +\<vars\><<< +static U_CHAR special_hd[10]; +>>> + + + + +\<process tex4ht special\><<< +try_new_line(); +switch( ch ){ + case '*': { `<other specials`> break; } + case '@': { `<insert char code`> break; } + case '+': { `<ivd code in main pass`> break; } + case '=': { `<insert verbatim record`> break; } + case '<': + case '>': { `<redirect html output`> break; } + case '!': { `<handle char map mode`> break; } + case '|': { gif_ch = !gif_ch; break; } + case ':': { `<arithmetics within specials`> break; } + case ';': { `<css for characters`> break; } + case '"': { `<positioned content`> break; } + case '~': { `<grouped-base delivery content`> break; } + case '.': { `<change ext of root file`> break; } + case '^': { `<classes for math symbols`> break; } +} +>>> + + +The \LinkPort\<handle requests for dvi to gif code\>{}handle requests ...\EndLink{} is +used for deciding which dvi code should be extracted for gif pictures. + + +\Verbatim +\specials within current version of TeX4ht + + \special{t4ht=...content...} + Insert the specified content to the html output, under + edef mode of processing, and without using the mapping + of the htf fonts. Used in \HCode{...}. + \special{t4ht>...file-name...} + Open a new file, if needed, and direct future output + to the specified file. Used in \File{...}. + \special{t4ht<...file-name...} + Close the specified file. Used in \EndFile{...}. + \special{t4ht++file-name}...dvi...\special{t4ht+} + Pipe the dvi code into a dvi page in the secondary dvi file + `jobname.idv'. Used by \Picture{...}, e.g., for requesting + gif's. + \special{t4ht+embeded-specials within idv} + \special{t4ht!...optional-parameters....}...dvi...\special{t4ht!} + Create an approximated character map for the dvi code. + Used in \Picture{...}, e.g., for ALT of IMG + \special{t4ht|}...\special{t4ht|} + Use the non-pictorial characters of the htf fonts. + Used for character maps of \Picture{....} + \special{t4ht@?...} string for marking errors in html output. + \special{t4ht@-}....\special{t4ht@-} + Remove left margin from character map. Used in \Picture{...}. + \special{t4ht@@}....\special{t4ht@@} + Insert the character codes, instead of their mappings through + the htf fonts. Used in \JavaScript... + \special{t4ht@...integer...} + Insert the character code to the output. + Used in \Char{-...}, typically, for characters out of the range + of the available keyboards and/or TeX output. + \special{t4ht@-...integer...} + Replace the character code introduced by the next character + with the current char code. + Used in \Char{...}, typically, for symbols out of the range + of the available keyboards and/or TeX output. Unlike \Char{-...}, + the current command inherites the font info from the next character + \special{t4ht@+...string...} + Replace the character code introduced by the next character + with the specified string. + Used in \Char{+...} and it inherites the font info from the + next character + \special{t4ht@+. ...string...} configure insertions at eoln + \special{t4ht@+(} ignore spaces + \special{t4ht@+)} end ignore spaces + \special{t4ht@+[} ignore chs and spaces + \special{t4ht@+]} end ignore chs and spaces + \special{t4ht@+!} get last ignored space (none, if from previous lines). + \special{t4ht+@...message...} + Send message to the lg file. Used in the \Needs{...} command. + \special{t4ht@/} on/off tracing of specials + \special{t4ht.extension for root file} + +Addition to next version of TeX4ht: + + \special{t4ht;....} + Decorations for htf characters. Useful,for instance, where + style sheets (like css) are available. Provide a full + solution for the problem of fonts, and eliminate the need + for the incomplete 'fonts' option of TeX4ht. Used in + \Configure{characters}..... + + \special{t4ht;8....} + No and EndNo for decorating characters. + +The next version of TeX4ht will probably also have the following +\special's, without yet fully employing their capabilities. + + \special{t4ht"...} + Request for positioned elements. Used only experimentally so far, + due to lack of sufficient support for such feature from + the available browsers. A possible alternative for pictorial + math and drawings. + \special{t4ht~...} + Grouped-base two-way delivery for content created by + inline commands like \over. Feature for xml-oriented + code. + \special{t4ht@_....} + Control output character for rulers. + \special{t4ht*<file} + Input file (with no processing) + \special{t4ht*! system comamnd} + System call + \special{t4ht@%*...open-del....*...close-del....} + Request partial dvi tracing. Not in current use, but might become + handy for postprocessors. + \special{t4ht:....} + Dvi-mode arithmetics. Not in current use, but might become + handy for postprocessors. + + + +\EndVerbatim + + +\ifHtml[\HPage{more}\Verbatim +Subject: Re: Dvi->HTML + +I attach the list of specials in TeX4ht. As you probably noticed, the +\special{t4ht=...} is the most prominnet one. The other specials are +rarely needed; I strongly propose you postpone using them until latter +stages of your work. I normally refer to such instructions indirectly +through low-level \HCode instructions, and high-level +\Configue... instructions. The web pages + + http://www.cse.ohio-state.edu/~gurari/tug97/ + +illustrate such usages. + +> My problem is -- glacing through the documentation -- + +Very little documentation is out, in particular for people that want +to change the system. Please don't hasitate to ask for help when you +need it. + +> I tried to find a way to use \special{t4ht=...} direct. +> Unfortunally do I fail, due to the missing comments in the *.sty and +> *.c files. Moreover the use of several macros makes the .c quite +> illegible :-( + +Agree. I can't read these files either. They are outputs of +literate programs. + +> Could you tell me which commands the .c program needs? +> It wouldd be sufficent if you would give the neccessary commands allown +> (a simple \special{t4ht=<HTML><HEAD></HEAD><BODY>...} does not work.) + +Try the following. + +1. Prepare a file x.tex having the following content. + + \special{t4ht=<HTML><HEAD></HEAD><BODY>} + Just trying. + \special{t4ht=</BODY></HTML>} + \bye + +2. Compile the file with tex (`tex x.tex'). + +3. Compile the outcome with tex4ht (`tex4ht x'). + +4. Visit the file x.html + +\EndVerbatim\EndHPage{}]\fi + +%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Insert Code (HCode)} +%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<insert verbatim record\><<< +while( special_n-- > 0 ){ + int ch; + BOOL flag; + struct hcode_repl_typ *q; + ch = get_char(); + q = hcode_repl; + flag = FALSE; + while( q != (struct hcode_repl_typ*) 0 ){ + if( ch == *(q->str) ){ flag = TRUE; break; } + q = q->next; + } + if( flag ){ + char *chr; + chr = (q->str) + 1; + while( *chr != 0 ){ put_char( *chr ); chr++; } + } else { put_char( ch ); } +} +>>> + +\List{*} +\item +\''\special{t4ht*=}' clears all the mappings of characters. +\item +\''\special{t4ht*=xx}' clears the mapping of the character `x'. +\item +\''\special{t4ht*=x....}' asigns a mapping to the character `x'. +\EndList + + +\<configure hcode\><<< + char *str, *repl; + struct hcode_repl_typ *p, *q; + BOOL flag; +if( special_n ){ + repl = str = m_alloc(char, (int) special_n + 1); + while( special_n-- > 0 ){ + *str = get_char(); str++; + } + *str = 0; + `<delete old hcode pattern`> + `<add new hcode pattern`> +} else { + `<delete all hcode patterns`> +} +>>> + +\<delete all hcode patterns\><<< +while( hcode_repl != (struct hcode_repl_typ*) 0 ){ + p = hcode_repl; + hcode_repl = hcode_repl->next; + free((void *) p->str); + free((void *) p); +} +>>> + + +\<delete old hcode pattern\><<< +if( hcode_repl != (struct hcode_repl_typ*) 0 ){ + if( *(hcode_repl->str) == *repl ){ + p = hcode_repl; + hcode_repl = hcode_repl->next; + free((void *) p->str); + free((void *) p); + } else { + p = hcode_repl; + while( TRUE ){ + q = p->next; + if( q == (struct hcode_repl_typ*) 0 ){ break; } + if( *(q->str) == *repl ){ + p->next = q->next; + free((void *) q->str); + free((void *) q); + break; + } + p = q; +} } } +>>> + + +\<add new hcode pattern\><<< +flag = *repl != *(repl+1); +if( !flag ){ flag = *(repl+2) != 0; } +if( flag ){ + p = (struct hcode_repl_typ *) m_alloc(struct hcode_repl_typ, 1); + p->str = repl; + p->next = hcode_repl; + hcode_repl = p; +} +>>> + + + +\<types\><<< +struct hcode_repl_typ { char *str; + struct hcode_repl_typ *next; }; +>>> + + +\<vars\><<< +static struct hcode_repl_typ *hcode_repl + = (struct hcode_repl_typ*) 0; +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Insert Char Code} +%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\`'\special{t4ht@i}' inserts the character code i, if +i is negative. If i is positive, the font info is sent as a replacement to +the next chracter code (allowing to use that letter character +font info for decoration). + + + + +The following is ignored within char maps, so we don't have +to worry about the bound of \`'\<design bound\>'. + +\<insert char code\><<< + int code, digit; +special_n--; +switch ( code = get_char() ){ + case '%': { `<dvi trace`> break; } + case '@': { verb_ch = !verb_ch; break; } + case '/': { `<on/off special trace`> break; } + case 'e': { `<get err str`> break; } + case '!': { `<recover ignored space`> break; } + case '(': { `<ignore spaces`> break; } + case ')': { `<end ignore spaces`> break; } + case '[': { `<ignore chs`> break; } + case ']': { `<end ignore chs`> break; } + case '?': { `<cond ignore chs`> break; } + case '-': { + if( special_n ) { code = 0; `<code := ...`> + put_char( code ); + } else { nomargin = TRUE; } + break; } + case '*': { `<send string to after next ch`> } + case '+': { `<send string to next ch`> break; } + case '.': { `<get eoln str`> break; } + case ',': { `<get space str`> break; } + case '_': { `<ruler ch`> break; } + case 'D': { `<write to lg file with loc stamp`> break; } + case 'u': { `<on/off unicode`> break; } + default: { `<send ch to next ch`> } +} +>>> + +\<vars\><<< +static BOOL nomargin = FALSE; +static int next_char = -1; +static U_CHAR *next_str = (char *) 0; +>>> + +\<defines\><<< +#define IGNORED void +>>> + +\<code := ...\><<< +while( special_n-- > 0 ){ + digit = get_char() - '0'; + if ( (digit < 0) || (digit > 9) ) { warn_i_int(41,digit+'0') ; } + else { code = code * 10 + digit; } +} +if ( (code < 0) || (code > 255) ) { code = '?'; warn_i_int(41,'?') ; } +>>> + +\<send ch to next ch\><<< +code -= '0'; `<code := ...`> next_char = code; +if( `<next-str`> ){ print_f(next_str); + free((void *) next_str); next_str = (char *) 0; } +>>> + + +Before reading a tring to be submitted forward, we look +for a previous submission. If such exists, we dump it. + +\<send string to next ch\><<< +if( `<next-char`> != -1 ) { + `<open output file`> + (IGNORED) put_4ht_ch( `<next-char`> , cur_o_file ); + `<next-char`> = -1; +} +if( `<next-str`> ){ print_f(next_str); + free((void *) next_str); next_str = (char *) 0; } +next_str = get_str( (int) special_n ); special_n = 0; +`<set indirect ch codes`> +>>> + +Indirect characters are expressed by character codes enclosed within +braces. For instance, `\Verb!\special{t4ht@+\string&{35}x0142;}x!'. + +\<set indirect ch codes\><<< +{ char *front, *back; + int i; + back = front = next_str; + while( *front != '\0' ){ + if( *front == '{' ){ + i = *(++front) - '0'; + while( *(++front) != '}' ){ i = i*10 + (*front - '0'); } + *front = (char) i; + } + *(back++) = *(front++); + } + *back = '\0'; +} +>>> + + + +\<next-char\><<< +next_char +>>> + + + +\<next-str\><<< +next_str +>>> + +\<send string to after next ch\><<< +keepChar=1; +>>> + + +\<current char for forwarded string\><<< +if( keepChar ){ + keepChar=FALSE; + { `<insert font char`> } +} +>>> + +% (IGNORED) put_4ht_ch( ch, cur_o_file ); + + +\<vars\><<< +static BOOL keepChar = FALSE; +>>> + + + + +%%%%%%%%%%%%%%%%% +\Section{Files} +%%%%%%%%%%%%%%%%% + +Whenever a new file is opened (\''\special{t4ht>...}'), its record is +placed on the top of a stack list. Whenever it is closed +(\''\special{t4ht<...}'), the record is removed from the stack, and +the file at the top of the stack get opened. A reopening of a file +doesn't affect the stack. + +The top of the stack is pointed by \`'opened_files', the next file +with \`'next', and the backward with \`'prev'. Each record also holds +a \`'from_file' pointer telling from where the file was last opened. + +One can ask for a return to the file that activated the current file +with the command \''\special{t4ht*>}', and to send the record to the +bottom of the stack with \''\special{t4ht*>file-name}'. + + +\<redirect html output\><<< +`<name = file name`> +`<open output file`> +`<p = pointer to file record`> +if( ch == '>' ){ `<open tex4ht file`> } +else { `<close tex4ht file`> } +cur_o_file = ( out_file == (FILE *) 0 )? root_file + : out_file; +>>> + + +\<retreat file\><<< +if( special_n > 0 ){ + `<send file record to bottom`> +} else { + `<back up to previous output file`> +} +>>> + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Open File} + +\<open tex4ht file\><<< +if( p != (struct files_rec*) 0 ){ + out_file = p->file; + p->prev_file = cur_o_file; + free((void *) name ); +} else { + if( !(*name) ) out_file = (FILE *) 0; + else { `<open non-root tex4ht file`> } +} +>>> + + +\<open non-root tex4ht file\><<< +p = m_alloc(struct files_rec, 1); +if( opened_files != (struct files_rec*) 0 ) opened_files->prev = p; +p->prev = (struct files_rec *) 0; +p->next = opened_files; opened_files = p; +p->name = name; +p->file = out_file = open_html_file(name); +p->prev_file = cur_o_file; +>>> + +\SubSection{Close File} + +\<close tex4ht file\><<< +if( p == (struct files_rec *) 0 ) bad_special( name ); +else { /* if p is null, do nothing more */ +`<fix pointers around file to be closed`> +if( opened_files != (struct files_rec*) 0 ) + { if( out_file == p->file ) out_file = opened_files->file; } +else out_file = (FILE *) 0; +(IGNORED) fclose( p->file ); free((void *) p->name ); +free((void *) p ); +} +>>> + + +\<fix pointers around file to be closed\><<< +if( p->prev != (struct files_rec*) 0 ) (p->prev)->next = p->next; +else opened_files = p->next; +if( p->next != (struct files_rec*) 0 ) (p->next)->prev = p->prev; +>>> + + + + + +\SubSection{Implicitly Closed Files} + +\<close active output files\><<< +while( opened_files != (struct files_rec*) 0 ) +{ + (IGNORED) fclose( opened_files->file ); + opened_files = opened_files->next; +} +>>> + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Backup to Previous File} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<back up to previous output file\><<< +`<find record of cur output file`> +>>> + +\<find record of cur output file\><<< + static struct files_rec *p, *q; +for( p = opened_files; p != (struct files_rec*) 0; p = p->next ){ + if( (p->file == cur_o_file) && p->prev_file ){ + `<error if prev file is closed`> + cur_o_file = p->prev_file; + p->prev_file = (FILE *) 0; + break; + } +} +>>> + +\<error if prev file is closed\><<< +for( q = opened_files; q != (struct files_rec*) 0; q = q->next ){ + if( q->file == p->prev_file ){ + break; + } +} +if( q == (struct files_rec*) 0 ){ + warn_i_str(51,q->name); + break; +} +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Intermediate Files to Bottom of Stack} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<send file record to bottom\><<< + static struct files_rec *p, *q; + U_CHAR name[256]; + int i; +`<find file record`> +if( p != (struct files_rec*) 0 ){ + `<move the file record`> +} +>>> + +\<find file record\><<< +i = 0; +name[(int) special_n] = '\0'; +while( special_n-- > 0 ){ name[i++] = get_char(); } +for( p = opened_files; p != (struct files_rec*) 0; p = p->next ){ + if( eq_str(p->name, name) ){ break; } +} +>>> + + + +\<move the file record\><<< +for( q = p; q->next != (struct files_rec*) 0; q = q->next ){ } +if( q != p ){ + q->next = p; + (p->next)->prev = p->prev; + if( opened_files == p ){ opened_files = p->next; } + else { (p->prev)->next = p->next; } + p->prev = q; + p->next = (struct files_rec*) 0; +} +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Get File Name} +%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<name = file name\><<< + int i=0; + U_CHAR *name; +name = m_alloc(char, (int) special_n+1); +*(name + (int) special_n) = '\0'; +while( special_n-- > 0 ) *(name + i++) = get_char(); +>>> + + +\SubSection{Find File Record} + + + + +\<p = pointer to file record\><<< +for( p = opened_files; p != (struct files_rec*) 0; p = p->next ) + { if( eq_str(p->name, name) ) break; } +>>> + + + + +\<vars\><<< +static struct files_rec + *opened_files = (struct files_rec *) 0, *p; +>>> + +\<defines\><<< +struct files_rec{ + FILE *file, *prev_file; + char* name; + struct files_rec *next, *prev; +}; +>>> + + + + + +\Section{Import Files, System Calls} + + + + +\<other specials\><<< +if( special_n ){ + special_n--; + switch ( get_char() ){ + case '<': { `<import file`> break; } + case '>': { `<retreat file`> break; } + case '!': { `<system call`> break; } + case '^': { `<accent specials`> break; } + case '@': { `<halign specials`> break; } + case '=': { `<configure hcode`> break; } + default: { `<consume unused specials`> } + } +} else { `<unused special`> } +>>> + + + +The library \`'<stdlib.h>' includes a function +\`'int system(const char *cmdstring);'. When cmdstring is NULL, +the return value is 0 iff the platform does not support system calls. + +\''mathml.4ht-9-22: \special{t4ht*!perl m2webeq > tmpa.tmp}%' + +\<system call\><<< + U_CHAR name[256], ch; + int i=0, n; + struct sys_call_rec *p; + BOOL flag; +name[(int) special_n] = '\0'; +while( special_n-- > 0 ){ name[i++] = get_char(); } +(IGNORED) printf("System call: %s\n", name); +`<flag = permission for system calls`> +if( flag ){ + (IGNORED) printf("System return: %d\n", + system_yes? (int) system(name) : -1 ); +} else { (IGNORED) printf("No permission for system call\n"); } +>>> + + + + +\<get from tex4ht.env file\><<< +(IGNORED) fseek(dot_file, 0L, `<abs file addr`>); +while ( search_dot_file( 'P' ) ){ struct sys_call_rec *q; + U_CHAR *p, str[256]; + q = m_alloc(struct sys_call_rec, 1); + q->next = system_calls; + system_calls = q; + p = str; + do + *(p++) = ch = (int) getc(dot_file); + while( (ch !='\n') && (ch != EOF) ); + p--; + *p = '\0'; + q->filter = m_alloc(char, (int) strlen((char *) str)+1); + (IGNORED) strcpy((char *) q->filter, (char *) str); +} +>>> + +\<permission for system calls\><<< +{ struct sys_call_rec *q; + q = m_alloc(struct sys_call_rec, 1); + q->next = system_calls; + q->filter = p + 2; + system_calls = q; +} +>>> + + +\<flag = permission for system calls\><<< +flag = FALSE; +p = system_calls; +while( p ){ + if( (n = (int) strlen((char *) p->filter)) == 1 ) { + flag = flag || (*(p->filter) == '*'); + } if( strlen((char *) name) >= (unsigned int) n ) { + ch = name[n]; name[n] = '\0'; + flag = flag || eq_str(p->filter,name); + name[n] = ch; + } + p = p->next; +} +>>> + +\<defines\><<< +struct sys_call_rec{ + char* filter; + struct sys_call_rec *next; +}; +>>> + + +\<vars\><<< +static BOOL system_yes; +static struct sys_call_rec *system_calls = (struct sys_call_rec *) 0; +>>> + +\<main's init\><<< +{ U_CHAR *yes = NULL; + system_yes = (system( yes ) != 0); +} +>>> + + +\<import file\><<< + U_CHAR name[256]; + int i=0; + FILE* file; +name[(int) special_n] = '\0'; +while( special_n-- > 0 ){ name[i++] = get_char(); } +file = f_open(name, READ_TEXT_FLAGS); +if( file ) { + `<open output file`> + while( (ch = getc(file)) >=0 ){ + (IGNORED) put_4ht_ch(ch,cur_o_file); + } + (IGNORED) fclose(file); +} else { warn_i_str( 1, name ); } +>>> + + + + +\Section{Arithmetics} + + + +\List{disc} + +\item \`':+...' increment by 1( define, if not defined) +\item \`':-...' decrement by 1 +\item \`':>...' push current value +\item \`':<...' pop current value +\item \`':!...' display current value +\item \`':|...' display top value +\EndList + +\<arithmetics within specials\><<< +if( special_n-- ){ + int code, n; + U_CHAR str [255], *p; + struct count_rec *q; + code = get_char(); + while( special_n > 254 ){ (void) get_char(); special_n--; } + p = str; n = special_n; + while( special_n-- ) { *(p++) = get_char(); } + *p = '\0'; + `<search counter`> + `<act on counter`> +} +>>> + + +\<types\><<< +struct count_rec{ + char* str; + int i, depth, max; + int* stack; + struct count_rec* next; +}; +>>> + +\<vars\><<< +static struct count_rec *counter = (struct count_rec *) 0; +>>> + +\<search counter\><<< +q = counter; +while( q ){ + if( eq_str(str,q->str) ) break; q = q->next; +} +if( !q ){ + q = m_alloc(struct count_rec, 1); + q->i = q->depth = 0; q->max = 10; + q->next = counter; counter = q; + q->str = m_alloc(char, (int) n+1); + (IGNORED) strcpy((char *) q->str, (char *) str ); + q->stack = m_alloc(int, q->max); +} +>>> + +\<push counter\><<< +if( q->depth == q->max ){ + q->max += 10; + if( (q->stack = (int *) r_alloc( (void *) q->stack, + (size_t) (q->max * sizeof(int)))) == NULL) bad_mem; +} +q->stack[q->depth++] = q->i; +>>> + +\<pop counter\><<< +q->depth--; +if( q->max > q->depth + 20 ){ q->max -= 15; + if( (q->stack = (int *) r_alloc( (void *) q->stack, + (size_t) (q->max * sizeof(int)))) == NULL) bad_mem; +} +>>> + +\<act on counter\><<< +switch ( code ){ + case '+': { (q->i)++; break; } + case '-': { (q->i)--; break; } + case '>': { `<push counter`> break; } + case '<': { if( q->depth ){ `<pop counter`> } + break; } + case '!': { `<open output file`> + (IGNORED) fprintf(cur_o_file, "%d", q->i); break; } + case '|': { if( q->depth ){ + `<open output file`> + (IGNORED) fprintf(cur_o_file, "%d", q->stack[q->depth - 1] ); + } + break; } + default: { ; } +} +>>> + + + + + + + + + + + + +\Chapter{Character Maps} + +\Section{Requests} + +\<handle char map mode\><<< +ch_map_flag = !ch_map_flag; +if( ch_map_flag ){ `<enter char map`> } +else { `<exit char map`> } +>>> + +\Section{Memory} + + +The character map is a sequence of lines that are dynamically +allocated. Each character is represented by a pair (str,design), where +str is a possible empty string and design is a character holding a +value 0, 1, 2, or 3. + +\<types\><<< +struct ch_map_rec{ + char* line; + int max, chars; +}; +>>> + + +\<vars\><<< +static struct ch_map_rec ch_map[HEIGHT]; +static int max_map_line, min_map_line; +>>> + +The following might be too high of a bound. The agreed def of html +allows only 1024 characters in a map. However, with the permissible +def of html, extra characters hopefully are ignored without causing +problems. Also note that we probably going to have leading and +trailing row that are not in use, and 120 line for a full page figure +is not relly that big of a bound on the numer of lines per page. + +\<defines\><<< +#define HEIGHT 120 +>>> + + +\<h ch\><<< +1>>> + +\<v ch\><<< +2>>> + +\<black ch\><<< +3>>> + +\<design bound\><<< +4>>> + + + +The str is a string holding the text that belongs +to the corresponding position: representation for the character, +specials, etc. The design hold a drawing content corresponding to +space, horizontal line, vertical line, and filled area, +respectively. If the str is empty, the design is assumed to be the +content of the character. If the string is not empty, it is assumed to +be the content of the character. + + +The string holds character codes in +the range of 32--255. Hence, we still have a room to get more +sophisticated designs. + + + +\<vars\><<< +static BOOL ch_map_flag = FALSE; +>>> + + + + + +\<defines\><<< +#define NULL_MAP (struct map_line_type*) 0 +>>> + + +\SubSection{Initialization} + +\List{$\circ$} + +\item \`'\special{t4ht!}' --- Default. +\item \`'\special{t4ht!i}'--- Magnified by i/100. +\item \`'\special{t4ht!i,j}'--- Magnified by (i/100,j/100). +\EndList + +\<enter char map\><<< +init_ch_map(); +xresolution = yresolution = 0; +while( special_n-- > 0 ){ + ch = get_char(); + if( (ch >= '0') && (ch <= '9') ) + { yresolution = yresolution * 10 + ch - '0'; } + else if( (ch == ',') && !xresolution && yresolution ) + { xresolution = yresolution; yresolution = 0; } + else { `<resolve boundary ch in maps`> } +} +if( !xresolution ) xresolution = yresolution; +if( !xresolution ){ xresolution = XRESOLUTION; + yresolution = YRESOLUTION; } +else { xresolution = xresolution * (INTEGER) (XRESOLUTION / 100); + yresolution = yresolution * (INTEGER) (YRESOLUTION / 100); } +>>> + + +Resolution can be an integer number or a pair of integer numbers +separated by a comma. The first for x-resolution, the second for +y-resolution. Then we can have a map for boundary characters made +up of pairs: character to be replaced followed by replcment. + +\<resolve boundary ch in maps\><<< +xresolution = yresolution = 0; +`<special resolution err`> +>>> + + + + + +\<vars\><<< +static INTEGER xresolution, yresolution; +>>> + + + + + + + + + + +\<defines\><<< +#define XRESOLUTION MARGINSP +#ifdef LONG +#define YRESOLUTION 786432L +#else +#define YRESOLUTION 786432 +#endif +>>> + + +\<header functions\><<<v +static void init_ch_map( ARG_I(void) ); +>>> + +\<functions\><<< +static void init_ch_map(MYVOID) +{ int i; + for( i=0; i<HEIGHT; i++ ){ + ch_map[i].max = 0; ch_map[i].chars = 0; ch_map[i].line = NULL; } + max_map_line = -1; + min_map_line = HEIGHT; +} +>>> + + +\Section{Fill Map} + + +\SubSection{With Characters} + +The 0.75 constant has been derived by trial and error by centering +the nodes of \`'\TreeSpec(\SRectNode)()() +\Tree()( + 3,dog// +0,boxer & 0,cocker & 3, schnauzer // +0,miniature~~schauzer & 0,standard~~schnauzer & 0,giant~~schnauzer// +)'. + +\<insert ch to ch-map\><<< +insert_ch_map((char) ch, TRUE); +>>> + +\<ch: 1, ruler: 0\><<< +tag>>> + + + +\<header functions\><<< +static void insert_ch_map( ARG_II(char,BOOL) ); +>>> + +\<functions\><<< +`[ +static void insert_ch_map( ch, `<ch: 1, ruler: 0`> ) + U_CHAR ch`; + BOOL `<ch: 1, ruler: 0`> + +;{ int row, col; + `<get row and col for ch`> + if(ch != 10){ + if( (ch_map[row].max > MAX_MAP_LINE) || (col > MAX_MAP_LINE) ){ + if( ok_map ){ warn_i_int_2( 25, MAX_MAP_LINE, ch); + ok_map = FALSE; } + }else{ `<adjust boundary ch`> + if( row < min_map_line ) min_map_line = row; + if( row > max_map_line ) max_map_line = row; + if( ch_map[row].max ){ `<insert char to nonempty map line`> } + else { `<insert char to empty map line`> } +} } } +>>> + + + + +Leave the following to the user responsibility of getting the char +mappings rightly in the `.htf' fonts. + +\Verbatim +\<adjust boundary ch NO\><<< +switch( ch ){ + case '>': { ch = 'x'; break; } + case '&': { ch = ''; break; } + case '"': { ch = ''; break; } +} +>>> +\EndVerbatim + +\<vars\><<< +static U_CHAR ok_map = TRUE; +>>> + + + +\<get row and col for ch\><<< +{ double x; + row = (int) ( (y_val>0? y_val : 0.0) / (double) yresolution + 0.5); + if( row >= HEIGHT ){ + if( ok_map ){ warn_i_int_2( 34, row, ch); ok_map = FALSE; } + return; } + x = (x_val>0? x_val : 0.0 ) / (double) xresolution + 0.75; + col = (int) x; + if( (ch > ' ') && (ch != '-') && (ch != '|') ){ + if( row == prevrow ){ + if( (col == prevcol + 1) && (x > prev_x + 0.5) ) + insert_ch_map(' ', TRUE); + else if( (col > prevcol + 1) && (x < prev_x+0.2) + && ( ch != '&' )) + col = prevcol + 1; + }else prevrow = -1; + prev_x = x + + (`<(double) char_width( design_ch? design_ch : ch )`>) + / (double) xresolution; + prevcol = col; + }else prevrow = -1; + prevrow = row; +} +>>> + + +The `{\tt( ch != '\&' )}' above is to avoid breaking indirect +unicode characters \`'&...;' in character maps. + + + + + +\<vars\><<< +static int prevcol = -1, prevrow; +static double prev_x; +>>> + + +\<defines\><<< +#define MAX_MAP_LINE 500 +>>> + + + + +\<insert char to empty map line\><<< + int n; + char* p; +ch_map[row].chars = (n = (col + 2 + 5) / 5 * 5) - `<ch: 1, ruler: 0`>; +ch_map[row].max = n - 1; +ch_map[row].line = p = m_alloc(char, n); +while( n-- ){ *(p++) = 0; } +*(ch_map[row].line + col) = ch; +>>> + + + + + + +\Verbatim +\<insert char to empty map lineNO\><<< + int n; + char* p; +ch_map[row].chars = (n = (col + 2 + 5) / 5 * 5) + - `<ch: 1, ruler: 0`>; +ch_map[row].max = n - 1; +ch_map[row].line = p = m_alloc(char, n); +while( n-- ){ *(p++) = 0; } +*(ch_map[row].line + col) = filter_bound_ch(ch); +>>> + +\EndVerbatim + + + +\<insert char to nonempty map line\><<< + int n; + char* p; +if( ch_map[row].chars > col ){ + `<insert char within map line`> } +else{ `<insert char beyond end of map line`> } +>>> + +Below: 8 = 1 (col starts at 0) + 2 (new ch=ch+bound) + 5 (rounding) + +The rounding to 5 to (hopefully) help garbage collection. + + + +\<insert char beyond end of map line\><<< +n = (col - ch_map[row].chars + 8) / 5 * 5; +ch_map[row].chars += n - `<ch: 1, ruler: 0`>; +ch_map[row].max += n; +ch_map[row].line = (char *) + r_alloc((void *) ch_map[row].line, + (size_t) ch_map[row].max + 1); +while( n-- ) *(ch_map[row].line + ch_map[row].max - n) = 0; +*(ch_map[row].line + ch_map[row].max + - (ch_map[row].chars - col) + !`<ch: 1, ruler: 0`> ) = ch; +>>> + + + + + + +\Verbatim +\<insert char beyond end of map lineNO\><<< +n = (col - ch_map[row].chars + 8) / 5 * 5; +ch_map[row].chars += n - `<ch: 1, ruler: 0`>; +ch_map[row].max += n; +ch_map[row].line = (char *) + r_alloc((void *) ch_map[row].line, + (size_t) ch_map[row].max + 1); +while( n-- ) *(ch_map[row].line + ch_map[row].max - n) = 0; +*(ch_map[row].line + ch_map[row].max + - (ch_map[row].chars - col) + !`<ch: 1, ruler: 0`> ) = + filter_bound_ch(ch); +>>> + +\EndVerbatim + + + + + +\<insert char within map line\><<< +if( `<ch: 1, ruler: 0`> ){ + if( *(ch_map[row].line + ch_map[row].max - 1) + || (ch_map[row].chars - col == 1) ){ `<get room for ch`> } + col = (ch_map[row].chars--) - col; + p = ch_map[row].line + ch_map[row].max; + while( col ){ unsigned char temp_ch; + if( ((unsigned char) (*p)) < `<design bound`> ) col--; + temp_ch = *(--p); *(p+1) = temp_ch; } +} else { + col = ch_map[row].chars - col; + p = ch_map[row].line + ch_map[row].max; + while( col ){ + if( ((unsigned char) (*p)) < `<design bound`> ) col--; p--; } +} +*(++p) = ch; +>>> + + + + + +\Verbatim +\<insert char within map lineNO\><<< +if( `<ch: 1, ruler: 0`> ){ + if( *(ch_map[row].line + ch_map[row].max - 1) + || (ch_map[row].chars - col == 1) ){ `<get room for ch`> } + col = (ch_map[row].chars--) - col; + p = ch_map[row].line + ch_map[row].max; + while( col ){ if( ((unsigned char) (*p)) < `<design bound`> ) col--; + *(p+1) = *(--p); } +} else { + col = ch_map[row].chars - col; + p = ch_map[row].line + ch_map[row].max; + while( col ){ + if( ((unsigned char) (*p)) < `<design bound`> ) col--; p--; } +} +*(++p) = filter_bound_ch(ch); +>>> + +\EndVerbatim + + + + +\<get room for ch\><<< +ch_map[row].max += 5; +ch_map[row].line = (char *) + r_alloc((void *) ch_map[row].line, + (size_t) ch_map[row].max + 1 ); +for( n = 0; n<5; n++ ) + *(ch_map[row].line + ch_map[row].max - n) = 0; +ch_map[row].chars += 5; +>>> + + +REMOVE FILTER!!!!!! + +\Verbatim +\<header functionsNO\><<< +INTEGER filter_bound_ch( ARG_I(INTEGER) ); +>>> + + +\EndVerbatim + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{With Rulers} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<ruler into ch map\><<< + long int sv_x_val, sv_y_val, sv_right, sv; + int ch; +sv_x_val = x_val; +sv_y_val = y_val; +sv_right = right; +y_val-=up; +if( right < 0 ){ x_val += right; right = -right; } +if( up < 0 ){ y_val += up; up = -up; } +ch = ( (right > xresolution) && (up > yresolution) ) ? + `<black ch`> : ( ( right > up )? `<h ch`> : `<v ch`> ); +right += x_val; +up += sv = y_val; +for( ; x_val < right; x_val += xresolution ) + for( y_val = sv ; y_val < up; y_val += yresolution ) + insert_ch_map((char) ch, FALSE); +x_val = sv_x_val; +y_val = sv_y_val; +if( sv_x_val + sv_right > max_x_val ) max_x_val = sv_x_val + sv_right; +if( `<ch: 1, ruler: 0`> ) x_val += sv_right; +>>> + + +\Section{Dump Map} + + + + + +\<exit char map\><<< +dump_ch_map(); +>>> + +We need memory of order 2 times the number of characters. + + +\<dump ch-map at end of page\><<< +if( ch_map_flag ){ + warn_i(27); `% dump_ch_map();`% init_ch_map(); } +>>> + +\`'dump_ch_map();' creates overflow problems here. + +\<header functions\><<< +static void dump_ch_map( ARG_I(void) ); +>>> + +% if( (min_map_line < 0) || (max_map_line >= HEIGHT) ){ return; } + + + +\<functions\><<< +static void dump_ch_map(MYVOID) +{ int n, i, min, k, extra_sp; + U_CHAR *p; + `% struct map_line_type *q; `% + `<min := start of bounding box`> + for( i=min_map_line; i<=max_map_line; i++ ){ + if( ( n = ch_map[i].max) > 0 ){ + p = ch_map[i].line; k = min; extra_sp = 0; + `<ignore trailing spaces`> + while( 1 + n-- ){ + if( --k < 0 ){ + if( extra_sp && (((unsigned char) *p) < `<design bound`>) + && (((unsigned char) *(p+1)) < `<design bound`>) ) + { extra_sp--; + } else { switch( *p ){ `<dump ch`> } } + } + p++; + } + free((void *) ch_map[i].line ); + } + if( i<max_map_line ) put_char('\n'); + } + nomargin = FALSE; +} +>>> + + + + +\<min := start of bounding box\><<< +{ int max; + min = 100; max = 0; + for( i=min_map_line; i<=max_map_line; i++ ){ + p = ch_map[i].line; + n = ch_map[i].max; if( max < n ) max = n; + k = 0; while( n-- ){ if(*(p++)) break; k++; } + if( ch_map[i].max && (k < min) ) min = k; } + if( (max < 78) && !nomargin ) min = 0; +} +>>> + + +\<ignore trailing spaces\><<< +{ U_CHAR *s; + s = p + n; + while( n && !(*s) && !(*(s-1)) ){ n--; s--; } + if( n && !(*s) && (((unsigned char) *(s-1)) < `<design bound`>) ) n--; +} +>>> + +\<dump ch\><<< + case 0: { put_char(' '); break; } + case `<h ch`>: { put_char('-'); break; } + case `<v ch`>: { put_char('|'); break; } +case `<black ch`>: { put_char('#'); break; } + case ' ': { extra_sp++; } + default: { `<insert ch from map into file`> break; } +>>> + +\<insert ch from map into file\><<< + BOOL tag; + INTEGER count; +tag = TRUE; count = 0; +do{ if( *p == '<' ) tag = FALSE; + else if( *p == '>' ) tag = TRUE; + else count += tag; + put_char( *p ); n--; +}while( ((unsigned char) *(++p)) >= `<design bound`> ); +if( !count ){ n++; p--; } +>>> + + +COUNT the number of characters and issue a warning if +over limit (1024 default). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Chapter{Extract Code of Figures} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%%%%%%%%%%%%%%%%%% +\Section{Outline} +%%%%%%%%%%%%%%%%%% + +A figure is taken to be a chunck of dvi code enclosed between +\`'+' specials. They are to be translated to, for instance, gif code. + +\<vars\><<< +static BOOL dvi_flag = FALSE, dvi_page = FALSE; +static FILE *idv_file; +>>> + +\<open idv file\><<< +job_name[job_name_n-1] = 'v'; +job_name[job_name_n-2] = 'd'; +job_name[job_name_n-3] = 'i'; +if( (idv_file = fopen(job_name, WRITE_BIN_FLAGS)) == NULL ) + bad_in_file(job_name); +`%job_name[job_name_n-3] = '\0';`% +>>> + + +\<main's vars\><<< +long int eof_op_n, begin_postamble; +int dis_pages; +>>> + + +\<extract dvi chunks\><<< +job_name[job_name_n-3] = '\0'; +`<extract preamble`> +page_n = 0; +`<start first idv page`> +while( dis_pages ){ `<extract pages`> } +`<error notice into lg`> +`<extract symbols`> +`<extract postamble`> +>>> + + + + +\<error notice into lg\><<< +if( errCode > 0 ){ + (IGNORED) fprintf(log_file, "tex4ht.c error: %d\n", errCode); +} +>>> + +\<vars\><<< +static int errCode = 0; +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Ignore in Main Pass} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +We had \`=case '+': {;}= before. However, this is wrong because we +want to do nothing here with regarding to directives for the gif part. + +\<ivd code in main pass\><<< +while( special_n-- > 0 ) (void) get_char(); +>>> + +%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Preamble} +%%%%%%%%%%%%%%%%%%%%%%%% + +\<extract preamble\><<< +file_n = 14; +(IGNORED) fseek(dvi_file, 0L, `<abs file addr`>); +do{ ch = get_char(); + idv_char( ch ); + file_n++; +}while( ch == `<no op`> ); +`<idv version`> +for( i=12; i ; i-- ){ idv_char( get_char() ); } +i = get_char(); +idv_char( (int) i ); while( i-- ) idv_copy(); +>>> + + +\<idv version\><<< +ch = get_char(); +if( id_version != -1 ){ ch = id_version; } +idv_char( ch ); +>>> + + +\<idv version replacement num\><<< +{ U_CHAR *q; + q = p + 2; + id_version = 0; + while( *q != '\0' ){ + if( id_version != -1 ){ + if( (*q < '0') || (*q > '9') ){ + id_version = -1; + warn_i(53); + } + id_version = id_version * 10 + *q - '0'; + } + q++; +} } +>>> + +\<vars\><<< +static int id_version = -1; +>>> + + +%%%%%%%%%%%%%%%%%%%% +\Section{Postamble} +%%%%%%%%%%%%%%%%%%%% + +\<extract postamble\><<< +idv_char(`<retrieve loc op`>); file_n += 2; +idv_char( `<end page op`> ); +(IGNORED) fseek(dvi_file, begin_postamble, `<abs file addr`>); +begin_postamble = file_n; +idv_char( `<begin-postamble op`> ); file_n += 5; +idv_int( bop_addr ); (IGNORED) fseek(dvi_file, 5L, `<relative file addr`>); +for( i = 20; i; i-- ) idv_copy(); +>>> + +\<extract postamble\><<< +i = (INTEGER) get_int(2) + 1; idv_char( (int) i >> 8 ); `%stack depth`% +idv_char( (int) i & 0xFF ); file_n += 2; +if( !page_n ) page_n++; idv_char( page_n >> 8 ); `%page number`% +idv_char( (int) page_n & 0xFF ); file_n += 2; +(IGNORED) fseek(dvi_file, 2L, `<relative file addr`>); +>>> + +\<extract postamble\><<< +eof_op_n -= 32; `%fonts`% +while( --eof_op_n ) idv_copy(); +idv_int(begin_postamble); `%start postamble`% +(IGNORED) fseek(dvi_file, 4L, `<relative file addr`>); file_n += 4; +`<idv version`> +for( i = 8 - file_n % 4; i; i-- ) idv_char( `<eof op`> ); +>>> + +%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Body} +%%%%%%%%%%%%%%%%%%%%%%%% + + +\<extract pages\><<< +if( (ch = get_char()) < 128 ) { visible_cnt = TRUE; cond_idv_char( ch );} +else switch( ch ){ `<chars for idv`> } +>>> + + + +\<chars for idv\><<< +case 128: case 129: case 130: case 131: case 133: +case 134: case 135: case 136: { + visible_cnt = TRUE; cond_string( ch, (ch - (ch>132)) % 4 +1 ); + break; +} +>>> + +Why the \`'cond_string' above? + + +\<chars for idv\><<< +case `<start page op`>: { + x_val = 0; y_val = 0; stack_n = 0; + (IGNORED) fseek(dvi_file, 44L, `<relative file addr`>); break; } +case `<end page op`>: { dis_pages--; } +case `<no op`>: { break; } +>>> + + +\<chars for idv\><<< +case `<mv hor dist dx.1`>: { + cond_idv_char( ch ); x_val += dx_1; break; } +case `<mv hor dist dx.2`>: { + cond_idv_char( ch ); x_val += dx_2; break; } +case `<mv ver dist dy.1`>: { + cond_idv_char( ch ); y_val += dy_1; break; } +case `<mv ver dist dy.2`>: { + cond_idv_char( ch ); y_val += dy_2; break; } +>>> + + +\<chars for idv\><<< +case `<mv hor 1-byte`>: case `<mv hor 2-byte`>: +case `<mv hor 3-byte`>: case `<mv hor 4-byte`>: { + cond_idv_char( ch ); + x_val += cond_int( ch - `<mv hor 1-byte`> + 1 ); break; } +case `<dx.1 store and mv hor 1-byte`>: +case `<dx.1 store and mv hor 2-byte`>: +case `<dx.1 store and mv hor 3-byte`>: +case `<dx.1 store and mv hor 4-byte`>: { + cond_idv_char( ch ); + dx_1 = (INTEGER) cond_int( ch - `<dx.1 store and mv hor 1-byte`> + 1); + x_val += dx_1; break; } +case `<dx.2 store and mv hor 1-byte`>: +case `<dx.2 store and mv hor 2-byte`>: +case `<dx.2 store and mv hor 3-byte`>: +case `<dx.2 store and mv hor 4-byte`>: { + cond_idv_char( ch ); + dx_2 = (INTEGER) cond_int( ch - `<dx.2 store and mv hor 1-byte`> + 1); + x_val += dx_2; break; } +>>> + +\<chars for idv\><<< +case `<mv ver 1-byte`>: case `<mv ver 2-byte`>: +case `<mv ver 3-byte`>: case `<mv ver 4-byte`>: { + cond_idv_char( ch ); + y_val += cond_int( ch - `<mv ver 1-byte`> + 1); + break; } +case `<dy.1 store and mv ver 1-byte`>: +case `<dy.1 store and mv ver 2-byte`>: +case `<dy.1 store and mv ver 3-byte`>: +case `<dy.1 store and mv ver 4-byte`>: { + cond_idv_char( ch ); + dy_1 = (INTEGER) cond_int( ch - `<dy.1 store and mv ver 1-byte`> + 1); + y_val += dy_1; break; } +case `<dy.2 store and mv ver 1-byte`>: +case `<dy.2 store and mv ver 2-byte`>: +case `<dy.2 store and mv ver 3-byte`>: +case `<dy.2 store and mv ver 4-byte`>: { + cond_idv_char( ch ); + dy_2 = (INTEGER) cond_int( ch - `<dy.2 store and mv ver 1-byte`> + 1); + y_val += dy_2; break; } +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Rules} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<chars for idv\><<< +case `<insert rule + move op`>:{ + visible_cnt = TRUE; cond_string( ch,4 ); x_val += cond_int(4); + break; +} +case `<insert rule + nomove op`>:{ + visible_cnt = TRUE; cond_string( ch, 8 ); + break; +} +>>> + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Specials} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Only \`'+' tex4ht specials are significant here. The ones of the form +\`'\special{t4ht++...}...\special{t4ht+}' act as delimiters for +segments of dvi code to be trasmitted to the dvi driver (probably +dvips). The other ones of the form \`'\special{t4ht+...}' are ignored +outside such segments, and are replaced by sub-specilas +\`'\special{...}' within the segments. For instance, +\`'\special{t4ht+ps:abc}' translates to \`'\special{ps:abc}' within +these segments. That is, the latter ones are indirect transpoters for +special code (why we need this transportes?). + +The non-tex4ht specials are introduced into the idv code. Those that +are parts of the picture environment, are included there (\''dvi_page=TRUE'). +Those that not, are included in separate pages. The latter ones might be +definitions and directives for the pictures, as is the case for pstricks +which sends them to dvips. + +\<chars for idv\><<< +case `<special 1`>: case `<special 2`>: +case `<special 3`>: case `<special 4`>: { long int i; + int special_nr; + special_nr = ch; + if( tex4ht_special( &ch, &i ) ){ + if( ch == '+' ){ + `<handle requests for dvi to gif code`> } + else while( i-- ) (void) get_char(); + }else if( dvi_flag ){ `<insert non-t4ht special into picture`> + }else { `<insert non-t4ht special on non-picture page`> } + break; +} +>>> + + + + +\<insert non-t4ht special on non-picture page\><<< +if( dvi_page || !page_n ){ dvi_page = FALSE; `<advance idv page`> } +dvi_flag = TRUE; +`<insert non-t4ht special`> +dvi_flag = FALSE; +>>> + +\<insert non-t4ht special on non-picture pageNO\><<< +while( i-- ) (IGNORED) get_char(); +>>> + +Replace the last piece with a seek! + (IGNORED) fseek(dvi_file, (long)i, `<relative file addr`>); + + +\<insert non-t4ht special into picture\><<< +visible_cnt = TRUE; `<insert non-t4ht special`> +>>> + + +\<insert non-t4ht special\><<< +{ + U_CHAR *ch; + int j; + ch = special_hd; + (IGNORED) putc( (unsigned) `<special 4`>, idv_file ); file_n++; + for(j=4; j--; ){ (IGNORED) putc( *ch, idv_file ); file_n++; ch++; } + while( *ch ){ (IGNORED) putc( *ch, idv_file ); file_n++; ch++; } + file_n += (int) i; + while( i-- ) (IGNORED) putc( get_char(), idv_file ); +} +>>> + + + + + +\<handle requests for dvi to gif code\><<< +if( i==0 ){ if( dvi_flag ){ dvi_flag = 0; `<end dvi page`> } } +else{ + if( dvi_flag ){ `<make a special for dvi driver`> } + else switch( get_char() ){ + case '+': { `<out gif filename`> + dvi_flag = TRUE; dvi_page = TRUE; + `<advance idv page`> break; } + case '@': { `<write to lg file`> break; } + default: { while( --i ) (void) get_char(); break; } +} } +>>> + + + +\<write to lg file\><<< +while( --i ) (void) putc( get_char(), log_file ); +(IGNORED) putc( '\n', log_file ); +>>> + + + + +\Verbatim +\<handle requests for dvi to gif codeNO\><<< +if( i==0 ){ if( dvi_flag ){ dvi_flag = 0; `<end dvi page`> } } +else{ + if( dvi_flag ){ `<make a special for dvi driver`> } + else if( '+'==get_char() ){ + `<out gif filename`> + dvi_flag = 1; `<advance idv page`> } + else while( --i ) (void) get_char(); +} +>>> + +\EndVerbatim + + + +\<out gif filename\><<< +{ U_CHAR str[256], *ch; + ch = str; while( --i ) *(ch++) = get_char(); *ch = '\0'; + script(font_gif, job_name ,page_n+1, str); +} +>>> + +\`'printf("%s", str);'--- tooo much info for screen, and not that significant. + + +\Verbatim +\<handle requests for dvi to gif codeNO\><<< +if( i ){ `<make a special for dvi driver`> } +else{ dvi_flag = !dvi_flag; + if( dvi_flag ){ `<advance idv page`> } + else { `<end dvi page`> } } +>>> +\EndVerbatim + + +\<make a special for dvi driver\><<< +cond_idv_char( special_nr ); +cond_idv_int( i, special_nr - `<special 1`> + 1 ); +while( i-- ) cond_idv_char( get_char() ); +visible_cnt = TRUE; +>>> + + +\<advance idv page\><<< +visible_cnt = FALSE; +bop_addr = advance_idv_page( bop_addr, cur_font ); +stack_depth = 0; +set_loc( `<mv hor 1-byte`>, x_val ); +set_loc( `<mv ver 1-byte`>, y_val ); +>>> + + + +\<idv vars\><<< +INTEGER bop_addr; +>>> + + +\<header functions\><<< +static void set_loc( ARG_II(int, long int) ); +>>> + +\<functions\><<< +`[ +static void set_loc( op, d ) + int op`; + long int d + +;{ + idv_char( op + 3 ); int_to_dvi( d, 4 ); file_n += 5; +} +>>> + +\SubSection{Stack} + +\<chars for idv\><<< +case `<sv loc op`>: { + push_stack(); + stack_depth++; + cond_idv_char( ch ); + break; } +case `<retrieve loc op`>: { INTEGER cur_x, cur_y; + stack_depth--; + cur_x = (INTEGER) x_val; cur_y = (INTEGER) y_val; pop_stack(); + if( dvi_flag ){ + if( stack_depth<0 ){ warn_i_int( 24, page_n ); + `<push curr state`> } + cond_idv_char( ch ); + } + break; } +>>> + +\<push curr state\><<< +cond_idv_char( `<mv hor 4-byte`> ); +idv_int( x_val - cur_x - dx_1 - dx_2 ); +cond_idv_char( `<dx.1 store and mv hor 4-byte`> ); +idv_int( dx_1 ); +cond_idv_char( `<dx.2 store and mv hor 4-byte`> ); +idv_int( dx_2 ); +cond_idv_char( `<mv ver 4-byte`> ); +idv_int( y_val - cur_y - dy_1 - dy_2 ); +cond_idv_char( `<dy.1 store and mv ver 4-byte`> ); +idv_int( dy_1 ); +cond_idv_char( `<dy.2 store and mv ver 4-byte`> ); +idv_int( dy_2 ); +cond_idv_char( `<sv loc op`> ); file_n += 24; +>>> + +\<end dvi page\><<< +if( !visible_cnt ) { U_CHAR str[256]; + (IGNORED) sprintf(str, "--- empty picture --- %sidv[%d] ---\n", + job_name,page_n); + (IGNORED) printf("%s", str); (IGNORED) fprintf(log_file, "%s",str); } +while( stack_depth-- > 0 ){ + idv_char(`<retrieve loc op`>); file_n++; } +>>> + + +\<idv vars\><<< +int stack_depth=0; +>>> + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Fonts Definition} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<chars for idv\><<< +case `<def 4 byte font`>: +case `<def 3 byte font`>: +case `<def 2 byte font`>: +case `<def 1 byte font`>: { idv_char( ch ); file_n++; + for( i=14; i; i-- ){ ch = get_char(); idv_char( ch ); file_n++; } + i = ch; i += ch = get_char(); idv_char( ch ); file_n++; + while( i-- ){ idv_copy(); } + break; } +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Fonts Activation} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +The following must be consisted with the usage +\`'for( i=1; i<=cur_font[0]; i++ ){'. + +\<chars for idv\><<< +case `<font 1-byte`>: +case `<font 2-bytes`>: +case `<font 3-bytes`>: +case `<font int`>: { int i; + idv_char( ch ); file_n++; + cur_font[0] = ch - `<font 1-byte`> + 2; + cur_font[1] = ch; + for( i=2; i <= cur_font[0]; i++ ){ + ch = get_char(); idv_char( ch ); + cur_font[i] = ch; file_n++; } + break; } +>>> + +\<chars for idv\><<< +default: { + if( (ch < `<font 0`>) || (ch > `<font 63`>) ){ + if( `<font defs for xdv's idv?`> ){ + `<xdv font def for idv`> + } else { err_i(23); } + } + else { idv_char( ch ); file_n++; + cur_font[0] = 1; cur_font[1] = ch; } + break; +} +>>> + +\<idv vars\><<< +char cur_font[6]; +BOOL visible_cnt=FALSE; +>>> + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Symbols from Fonts} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<extract symbols\><<< +{ int ch, i, mag; + U_CHAR str[256]; + (IGNORED) fprintf(log_file, "%s", begin_char_gif); + dvi_flag = TRUE; + for( cur_fnt = font_tbl_size; cur_fnt--; ){ + `<output to lg file`> + for( i = font_tbl[cur_fnt].char_l - font_tbl[cur_fnt].char_f + 1; + i--; ) + if( get_bit( font_tbl[cur_fnt].gif_on, i) ){ + bop_addr = advance_idv_page( bop_addr, cur_font ); + set_loc( `<mv hor 1-byte`>, (long int) mid_page_x ); + set_loc( `<mv ver 1-byte`>, (long int) mid_page_y ); + `<get font of symbol`> + `<insert the char code`> } + } + (IGNORED) printf("Execute script ``%slg'\n", + job_name); + (IGNORED) fclose( log_file ); +} +>>> + + + + + + + +\<insert the char code\><<< +if( (ch = i + font_tbl[cur_fnt].char_f) > 127 ) { + if( ch < 256 ) cond_idv_char(133); else warn_i(23); } +cond_idv_char( ch ); +mag = (int) ((double) font_tbl[cur_fnt].scale / + font_tbl[cur_fnt].design_sz * 10 ); +`<insert gif symbol to lg file`> +script(font_gif, job_name ,page_n, str); +>>> + +\`'printf("%s", str);' --- too mach info + +\<open log file\><<< +{ U_CHAR str[256]; + (IGNORED) strcpy((char *) str, (char *) job_name); + str[job_name_n-1] = '\0'; + str[job_name_n-2] = 'g'; + str[job_name_n-3] = 'l'; + if( (log_file = fopen(str, WRITE_TEXT_FLAGS)) == NULL ) + bad_in_file(str); +} +>>> + +\<vars\><<< +static FILE* log_file; +>>> + +\<max page dimensions\><<< +mid_page_y = (INTEGER) get_unt(4) / 2; +mid_page_x = (INTEGER) get_unt(4) / 2; +>>> + +\<vars\><<< +static INTEGER mid_page_y, mid_page_x; +>>> + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Activate Font} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<get font of symbol\><<< +{ INTEGER num; + num = font_tbl[cur_fnt].num; + if( num <= `<number of direct fonts`> ) + cond_idv_char( (int) (num + `<font 0`>) ); + else if( dvi_flag ){ + if( (num < 0) || (num > 16777215L) ) idv_int(`<font int`>); + else if( num < 256 ) { idv_char(`<font 1-byte`>); file_n++; } + else if( num < 65536L ) int_to_dvi((long int) `<font 2-bytes`>,2); + else int_to_dvi((long int) `<font 3-bytes`>,3); + cond_idv_char( (int) num ); +} } +>>> + +The above seems to be incorrect for big numbers!!!!!!!!!!!!!! + +\Section{Utilities} + + +\<header functions\><<< +static void idv_char( ARG_I(int) ); +>>> + +\<functions\><<< +`[ +static void idv_char( n ) int n +;{ (IGNORED) putc( n, idv_file ); } +>>> + + + + +\<header functions\><<< +static void cond_idv_char( ARG_I(int) ); +>>> + +\<functions\><<< +`[ +static void cond_idv_char( n ) int n +;{ + if( dvi_flag ){ (IGNORED) putc( n, idv_file ); file_n++; } +} +>>> + + + + +\<header functions\><<< +static void idv_copy( ARG_I(void) ); +>>> + +\<functions\><<< +static void idv_copy( MYVOID ) +{ idv_char( get_char() ); file_n++; } +>>> +\<defines\><<< +#define idv_int(val) int_to_dvi((long int) val,4) +>>> + + + + +\<header functions\><<< +static void cond_idv_int( ARG_II(long int, int) ); +>>> + +\<functions\><<< +`[ +static void cond_idv_int( val, n ) long int val`; + int n +;{ + if( dvi_flag ){ int_to_dvi((long int) val, n ); file_n += n; } +} +>>> + + +\<header functions\><<< +static void int_to_dvi( ARG_II(long int, int) ); +>>> + +\<functions\><<< +`[ +static void int_to_dvi( val, n ) long int val`; + int n + +;{ unsigned U_CHAR ch2, ch3, ch4; + ch4 = (unsigned char) (val & 0xFF); val = val >> 8; + ch3 = (unsigned char) (val & 0xFF); val = val >> 8; + ch2 = (unsigned char) (val & 0xFF); val = val >> 8; + switch( n ){ + case 4: idv_char( (int) val ); + case 3: idv_char( ch2 ); + case 2: idv_char( ch3 ); + case 1: idv_char( ch4 ); } +`% if( val & 0x80 ) val -= 0x100;`% +} +>>> + +\<header functions\><<< +static void cond_string( ARG_II(int, int) ); +>>> + +\<functions\><<< +`[ +static void cond_string(ch, n) int ch`; int n + +;{ cond_idv_char( ch ); + while( n-- ) cond_idv_char( get_char() ); +} +>>> + + +\SubSection{Advance Page} + + +\<start first idv page\><<< +x_val = 0; y_val = 0; stack_n = 0; +idv_char( `<start page op`> ); +idv_int( page_n + 1 ); for( i=36; i--; ) idv_char( 0); +idv_int( -1 ); bop_addr = file_n; file_n += 45; +idv_char(`<sv loc op`>); file_n++; +>>> + +\<vars\><<< +static int page_n, file_n; +>>> + + +\<header functions\><<< +static INTEGER advance_idv_page( ARG_II( INTEGER,char*) ); +>>> + +\<functions\><<< +`[ +static INTEGER advance_idv_page( bop_addr, cur_font ) + INTEGER bop_addr`; + char* cur_font + +;{ int i; + if( page_n++ ){ + idv_char(`<retrieve loc op`>); file_n++; + idv_char(`<end page op`>); file_n++; + idv_char( `<start page op`> ); + idv_int( page_n ); for( i=36; i--; ) idv_char( 0); + idv_int( bop_addr ); bop_addr = file_n; file_n += 45; + idv_char(`<sv loc op`>); file_n++; + for( i=1; i<=cur_font[0]; i++ ){ + idv_char( cur_font[i] ); file_n++; + } } + `<set dx-1, dx-2, dy-1, dy-2`> + return bop_addr; +} +>>> + +What \`'cur_font[0]' holds? + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Set Store-Move Variables} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Dvips requires font definitions before the following code in the first +dvi page. + +\<set dx-1, dx-2, dy-1, dy-2\><<< +store_mv(`<dx.1 store and mv hor 4-byte`>, dx_1); +store_mv(`<dx.2 store and mv hor 4-byte`>, dx_2); +store_mv(`<dy.1 store and mv ver 4-byte`>, dy_1); +store_mv(`<dy.2 store and mv ver 4-byte`>, dy_2); +>>> + +\<header functions\><<< +static void store_mv( ARG_II( int, INTEGER) ); +>>> + + +\<functionsNO-sep-9\><<< +`[ +static void store_mv(op, d) int op`; INTEGER d + +;{ + cond_idv_char(op); cond_idv_int( (INTEGER) -d); + cond_idv_char(op); cond_idv_int( (INTEGER) d); +} +>>> + + + + +\<functions\><<< +`[ +static void store_mv(op, d) int op`; INTEGER d + +;{ + if( dvi_flag ){ + cond_idv_char(op); idv_int( (INTEGER) -d); + cond_idv_char(op); idv_int( (INTEGER) d); file_n += 8; } +} +>>> + + +\Chapter{Tables} + + + + + + +\Section{The Options} + +In TeX, we initiate tables of the form + +\Verbatim +\haligh{ + ... & ... & ... \cr + ... & ... & ... \cr +} +\EndVerbatim + +Such tables translate to dvi tables of the form + +\Verbatim +<group> + <group> ... </group> + <group> ... </group> + <group> ... </group> +</group> + +<group> + <group> ... </group> + <group> ... </group> + <group> ... </group> +</group> +\EndVerbatim + +The option \`'@' asks to start puting the entries over +the following groups. + +Two problems arise: + +\List{a} +\item + Unless the tables are followed by +external end-groups, we don't have any mark telling where they end. + The \`'/' special can be used in the sources to identify the +ends. + +\item The \`'\nohalign' commands provide dirty entries between the rows. + +\EndList + + + + + + +\<halign specials\><<< + int i; +i = 0; +special_n--; +switch ( get_char() ){ + case '8': { i++; } + case '7': { i++; } + case '6': { i++; } + case '5': { i++; } + case '4': { i++; } + case '3': { i++; } + case '2': { i++; } + case '1': { `<new halign setting`> break; } + case '/': { if( special_n ){ + `<consume unused specials`> + } else { `<output end halign table`> } + break; + } + case '&': { i++; } + case '@': { i++; + if( special_n ){ + `<consume unused specials`> + } else { + `<start halign table`> + } + break; + } + default: { `<consume unused specials`> } +} +>>> + + + + + + + + + +\Section{Info for Entries} + +\SubSection{Inilialization of Base} + + The base entries are stored in a set of global variables + \`'str[i]', and the number of usages is stored in + \`'refs[i]'. The strings can be used from the global shared base + or the local groups. + + + +\<vars\><<< +static struct halign_rec *halign[8]; +>>> + +\<defines\><<< +struct halign_rec{ + char * str; + int refs; +}; +>>> + +\<main's init\><<< +{ int i; + for( i=8; i--; ){ + halign[i] = m_alloc(struct halign_rec, 1); + halign[i]->str = m_alloc(char, 1); + *(halign[i]->str) = '\0'; + halign[i]->refs = 1; + } +} +>>> + +\SubSection{Modifications to Base} + +\<new halign setting\><<< +if( halign[i]->refs == 1 ){ + free((void *) halign[i]->str ); +} else { + (halign[i]->refs)--; + halign[i] = m_alloc(struct halign_rec, 1); + halign[i]->refs = 1; +} +halign[i]->str = get_str( (int) special_n ); +special_n=0; +>>> + + + + + + + + + + + + + + + + +\SubSection{Initializations for Groups} + + + Each group level has its local set of variables. Whenever a + request \`'@' or \`'&'arrives, we verify that the the local entries + equal to the current global entries. If not, the local entries are + replaced with copies of the current ones. + +\<struct stack_entry\><<< +struct halign_rec *halign[8]; +BOOL halign_on, halign_info, row_no, col_no; +>>> + + +\<initialized entries for grouping stack\><<< +stack[i].halign_info = FALSE; +stack[i].halign_on = FALSE; +>>> + + + + + +\SubSection{Modifications for Groups at Requests} + +Upon requesting an insertion for \''\halign', through +\''\special{t4ht*@}' or \''\special{t4ht*&}', we modify the +entries on the current group. + + +\<start halign table\><<< +new_halign = i * TRUE; +>>> + +\<vars\><<< +static BOOL new_halign = FALSE; +>>> + + + + +\<insert start of halign\><<< +stack[stack_n].halign_on = new_halign; +if( stack[stack_n].halign_info ) +{ int j; + for( j=8; j--; ){ + if( stack[stack_n].halign[j] != halign[j] ){ + if( ! (--(stack[stack_n].halign[j]->refs) ) ){ + free((void *) stack[stack_n].halign[j]->str ); + free((void *) stack[stack_n].halign[j] ); + } + stack[stack_n].halign[j] = halign[j]; + (halign[j]->refs)++; + } + } +} else { int j; + stack[stack_n].halign_info = TRUE; + for( j=8; j--; ){ + stack[stack_n].halign[j] = halign[j]; + (halign[j]->refs)++; +} } +print_f( stack[stack_n].halign[0]->str ); +stack[stack_n].row_no = 0; +new_halign = FALSE; +>>> + + + +\SubSection{Release at Starts of Groups} + +The following are for introducing tabular tags for containing rows and +cols of tables. They are encounter before \''stack_n' changes its +value. + +\<halign at entry to group\><<< +if( new_halign ){ + `<insert start of halign`> +} +if( stack[stack_n].halign_on ) +{ + print_f( stack[stack_n].halign[2]->str ); + if( stack[stack_n].halign_on > TRUE ){ + stack[stack_n].row_no++; + stack[stack_n].col_no = 0; + (IGNORED) fprintf(cur_o_file, "%d%s", + stack[stack_n].row_no, stack[stack_n].halign[6]->str ); +} } +if( stack_n ){ + if( stack[stack_n-1].halign_on ) + { + print_f( stack[stack_n-1].halign[4]->str ); + if( stack[stack_n-1].halign_on > TRUE ){ + stack[stack_n-1].col_no ++; + (IGNORED) fprintf(cur_o_file, "%d%s", + stack[stack_n-1].col_no, stack[stack_n-1].halign[7]->str ); + } +} } +>>> + + +\SubSection{Release at Ends of Groups} + + +\<halign at exit from group\><<< +`<output end halign table`> +`<output end halign row`> +`<output end halign col`> +if( stack[stack_n].halign_info ) +{ int j; + for( j=8; j--; ){ + if( ! (--(stack[stack_n].halign[j]->refs) ) ){ + free((void *) stack[stack_n].halign[j]->str ); + free((void *) stack[stack_n].halign[j] ); + } } + stack[stack_n].halign_info = FALSE; +} +>>> + +The ouput for end of table is for the current level of table, for end +of row is an immediately containig tables, and for a col is for second +generation containing table. + +\<auto quit halign\><<< +if( stack[stack_n].halign_on ) +{ + switch( ch ){ + case `<mv ver 1-byte`>: { ; } + case `<mv ver 2-byte`>: { ; } + case `<mv ver 3-byte`>: { ; } + case `<mv ver 4-byte`>: { ; } + case `<mv ver dist dy.1`>: { ; } + case `<dy.1 store and mv ver 1-byte`>: { ; } + case `<dy.1 store and mv ver 2-byte`>: { ; } + case `<dy.1 store and mv ver 3-byte`>: { ; } + case `<dy.1 store and mv ver 4-byte`>: { ; } + case `<mv ver dist dy.2`>: { ; } + case `<dy.2 store and mv ver 1-byte`>: { ; } + case `<dy.2 store and mv ver 2-byte`>: { ; } + case `<dy.2 store and mv ver 3-byte`>: { ; } + case `<dy.2 store and mv ver 4-byte`>: { ; } + case `<insert rule + move op`>: { ; } + case `<insert rule + nomove op`>: { ; } + case `<font 1-byte`>: { ; } + case `<font 2-bytes`>: { ; } + case `<font 3-bytes`>: { ; } + case `<font int`>: { ; } + case `<sv loc op`>: + { break; } + default: { `<print end of halign table`> } +} } +>>> + +\<output end halign table\><<< +if( stack[stack_n].halign_on ) +{ `<print end of halign table`> } +>>> + + +\<print end of halign table\><<< +print_f( stack[stack_n].halign[1]->str ); +stack[stack_n].halign_on = FALSE; +>>> + + + +\<output end halign row\><<< +if( stack_n ){ + if( stack[stack_n-1].halign_on ) + { + print_f( stack[stack_n-1].halign[3]->str ); +} } +>>> + + +\<output end halign col\><<< +if( stack_n-1 ){ + if( stack[stack_n-2].halign_on ) + { + print_f( stack[stack_n-2].halign[5]->str ); +} } +>>> + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Chapter{Groups and Group-Based Inline Operations} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +For instance, \''\over'. Such operations require delivery of +information backward and forward to the group boundaries. +For backward delivery, a preprocessing phase is introduced. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Data Transfer} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + + +Upon encountering a \''\special{t4ht~...}' we arrive here. An empty +content is an on/off flag. When it is turned on, we make a +preprocessing pass to collect information. + + + +\List{*} +\item \`'\special{t4ht\string~} ... \special{t4ht\string~}' --- start +/ end switches for backward submissions. + +\item +\`'\special{t4ht\string~<i...}', \`'\special{t4ht\string~>i...}' --- +send to group at relative level i. + + +\item +\`'\special{t4ht\string~<*...}' --- send back to start of previous +token / group. + +\item \`'\special{t4ht~<[}...\special{t4ht~<]}' --- hide region +from back token / group submission + + +\item \`'\special{t4ht~<-} ... \special{t4ht~<+}' --- latex mode +of token / group submissions (what is that???) + +\item \`'\special{t4ht~<)} \special{t4ht~<(}...\special{t4ht~<)}' +--- activate / hide back token / group submissions + + + + + + +\EndList + + + + + +\<grouped-base delivery content\><<< +if( special_n ){ + `<main pass for group special`> +} else if( (group_dvi = !group_dvi) == TRUE ){ + long curr_pos; + int ch, sv_stack_n; + `<subp vars`> + `<init subp vars`> stack_id = 0; + curr_pos = ftell(dvi_file); sv_stack_n = stack_n; + `<send info backward`> + `<exit early pass`> + (IGNORED) fseek(dvi_file, curr_pos, `<abs file addr`>); + group_dvi = TRUE; stack_n = sv_stack_n; stack_id = 0; +} else { `<exit group special`> } +>>> + + +% SEEK_SET); + +\<vars\><<< +static BOOL group_dvi = FALSE; +>>> + +\<main's vars\><<< +int stack_id=0; +>>> + + +\SubSection{Main Pass} + + +\<main pass for group special\><<< + U_CHAR in_ch; +if( (in_ch = get_char()) == '>' ) { + `<store forward submissions`> +} else if( in_ch == '!' ) { + `<store path-based forward submissions`> +} else { + if( !group_dvi ){ warn_i(42); } + (IGNORED) fseek(dvi_file, (long) --special_n, + `<relative file addr`>); + special_n = 0; +} +>>> + + + + + + + + + + + + +\ifHtml[\HPage{example}\Verbatim + + +\def\:temp{\special{t4ht\string~<<NOMINATOR>}\HCode{</NOMINATOR><DENOMINATOR>}\o:over: + \special{t4ht\string~></DENOMINATOR>}} +\Let\over=\:temp + + +aa +\special{t4ht\string~}$ +{A \over B} \over C +$\special{t4ht\string~} + + +\EndVerbatim\EndHPage{}]\fi + + + + + + + + +%%%%%%%%%%%%%%%%%%%%% +\SubSection{Memory} +%%%%%%%%%%%%%%%%%%%%% + +\<vars\><<< +static int stack_n = 0; +static struct stack_entry* stack; +>>> + +\<types\><<< +struct stack_entry{ + long int x_val, y_val; + INTEGER dx_1, dx_2, dy_1, dy_2; + BOOL text_on; + BOOL `<BOOl stack accented`>; + `<struct stack_entry`> +}; +>>> + +\<stack = m-alloc...\><<< +stack = m_alloc(struct stack_entry,`<size of stack for nested boxes`>); +`<initialize grouping stack`> +>>> + +\<size of stack for nested boxes\><<< +((int) stack_len + 2) +>>> + +The \`'\special{t4ht^>*...*...}' asks for delimiters on the next group +or token, whichever comes first. That information is stored in the +stack even for characters, which implies an implicit stack greater by +one than that requested by the dvi code. The extra 2 in size reults +from the pointer being on the next empty entry? + +% (IGNORED) fprintf(cur_o_file, "\n..end := begin := 0.......%d-%d",stack_id,stack_n); + + +\<struct stack_entry\><<< +int stack_id; +struct group_info * begin; +struct stack_end_entry * end; +>>> + + +\<types\><<< +struct group_info{ + int stack_id; + U_CHAR *info; + struct group_info* next; +}; +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Initialization} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<initialize grouping stack\><<< +{ int i; + for( i=`<size of stack for nested boxes`>-1; i>=0; i--){ + stack[i].begin = (struct group_info *) 0; + stack[i].end = (struct stack_end_entry *) 0; + stack[i].stack_id = -1; + `<initialized entries for grouping stack`> +} } +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Submissions and Retievals} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\SubSection{``Forward'' to End of Group} + +\<store forward submissions\><<< +if( special_n == 1 ){ + special_n--; + switch( get_char() ){ + case '[': { ignore_end_group++; break; } + case ']': { ignore_end_group--; break; } + default: { `<unused special`> } + } +} else { + struct stack_end_entry *p; + U_CHAR *q; + int j; + j = get_char() - '0' + stack_n - 1; + if( --special_n ){ + if (j >= stack_len ) { j = stack_len - 1; } + p = m_alloc(struct stack_end_entry,1); + p->next = stack[ j ].end; + stack[ j ].end = p; + q = p->send = m_alloc(char,special_n+1); + while( --special_n ) *q++ = get_char(); + *q = '\0'; +} } +>>> + + +We create a linked list for forward submissions. + + +\<types\><<< +struct stack_end_entry{ + struct stack_end_entry *next; + U_CHAR *send; +}; +>>> + + +\<retrieve forward submissions\><<< + struct stack_end_entry *q, *p, *t; +q = stack[ stack_n-1 ].end; +p = stack[ stack_n-1 ].end = (struct stack_end_entry *) 0; +while( q ){ + t = q->next; q->next = p; p = q; q = t; +} +while( p ){ + if( ! ignore_end_group ){ print_f( p->send ); } + free((void *) p->send ); + q = p; p = p->next; free((void *) q ); +} +>>> + + + +% (IGNORED) fprintf(cur_o_file, "\n%d. SEND FORWARD.........stack[%d] [SEND %s]\n", +% stack_id, stack_n-1, stack[ stack_n-1 ].end); + + + + +\<get forward deliveries\><<< +while( stack[stack_n-1].end ){ + `<retrieve forward submissions`> +} +>>> + +\<vars\><<< +static int ignore_end_group; +>>> + + + + + +% (IGNORED) fprintf(cur_o_file, "\n%d. GET FORWARD.........stack[%d] [GET: %s]\n", +% stack_id, stack_n, stack[ stack_n ].end); + + + + + +\<exit group special\><<< +{ int stack_n; + for( stack_n=`<size of stack for nested boxes`>; + stack_n>0; stack_n--){ + group_dvi = TRUE; `<get forward deliveries`> + group_dvi =FALSE; + `<check forward deliveries`> +} } +>>> + + +\<check forward deliveries\><<< +while( stack[stack_n-1].begin ){ + struct group_info *p; + warn_i_str(44, stack[stack_n-1].begin->info); + p = stack[stack_n-1].begin; + stack[stack_n-1].begin = p->next; + free((void *) p ); +} +stack[stack_n-1].stack_id = -1; +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{``Backward'' to Begin of Groups} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +The following is needed for pops that appear before the leading push. +Such pops can emerge from preceding code. + + + +\<send info back to group open\><<< + struct group_info *p; + U_CHAR *q; + int j; +j = ch - '0' + stack_n - 1; +if (j >= stack_len ) { j = stack_len - 1; } +p = m_alloc(struct group_info,1); +p->next = stack[ j ].begin; stack[ j ].begin = p; +p->stack_id = stack[ j ].stack_id; +q = p->info = m_alloc(char,i+1); +while( --i ) *q++ = get_char(); +*q = '\0'; +>>> + +``Backward'' submissions to levels higher than 0 are forward +transmission and they can be moved to the main pass. That will buy +a little saving in memory, and possibly less fragmentation there +due to dynamic allocation of mem. + + + + + +% stack[stack_n].end = (struct stack_end_entry *) 0; + +\<push/pop on backward submissions\><<< +case `<sv loc op`>: { + `<stack-id into linked list`> + stack[stack_n].stack_id = stack_id++; + `<push-id + 1`> stack_n++; + if( stack_n > `<size of stack for nested boxes`> ){ warn_i(40); } + break; +} +case `<retrieve loc op`>: { + stack_n--; `<pop-id + 1`> + stack[stack_n].stack_id = -1; + break; +} +>>> + +The following changes the previously unknown stack-id, represented by +-1, of a future deeper PUSH with the stack-id of that PUSH. That PUSH +is just have been reached. We also want to reverse the order within +that sub-list. + +\<stack-id into linked list\><<< +{ struct group_info *p, *last; + if( (last = p = stack[ stack_n ].begin) != (struct group_info *)0 ) + if( p->stack_id == -1 ){ + `<modify id of sub sequence`> + `<reverse stack sub sequence`> + } +} +>>> + +\<modify id of sub sequence\><<< +while( p ){ + if( p->stack_id != -1 ){ break; } + p->stack_id = stack_id; + last = p; + p = p->next; +} +>>> + + +\<reverse stack sub sequence\><<< +while ( stack[ stack_n ].begin != last ){ + p = (stack[ stack_n ].begin) -> next; + (stack[ stack_n ].begin) -> next = last->next; + last->next = stack[ stack_n ].begin; + stack[ stack_n ].begin = p; +} +>>> + + + +\<get backward deliveries\><<< +{ struct group_info *p; + if( group_dvi && + ( (p = stack[stack_n].begin ) != (struct group_info *)0) + ){ + while( p ){ + if( p->stack_id != stack_id ) break; + print_f(p->info); + stack[stack_n].begin = p->next; + free((void *) p ); + p = stack[stack_n].begin; + } + } + stack_id++; +} +>>> + + +% if( group_dvi ){ +% (IGNORED) fprintf(cur_o_file, "\n..%d.......%d-%d", +% stack[stack_n].begin,stack_id,stack_n); +% } + + + +% (IGNORED) fprintf(cur_o_file, + % "\n%d. GET BACKWARD.........stack[%d]=%d \n", + % stack_id, stack_n,stack_id); + + +The following reverses the list at the end of the preprocessing pass. + +\<exit early pass\><<< +{ struct group_info *first, *second, *temp; + int i; +for(i = stack_len; i >= 0; i--){ + first = stack[i].begin; + if( first ) { + second = first->next; + while( second ){ + temp = second->next; + second->next = first; + first = second; + second = temp; + } + (stack[i].begin)->next = (struct group_info *) 0; + stack[i].begin = first; +} } } +>>> + + + + +\Section{Preprocessing Pass} + +Used for collecting information to be sent backward to the entry +point of the group. The information is stored in linked lists +of type \`'struct group_info', accessed through +\`'stack[ level-of-nesting ].begin'. + +Each PUSH is offered an id. Upon reaching a PUSH, its id is stored in +\`'stack[ level-of-nesting ].stack_id'. Upon reaching a +\`'\special{t4ht~<...message...}', the message is inserted into the linked +list, together with its PUSH id. The messages are retrieved in the +main pass, as the PUSHES are traversed for the second time. + + +\<send info backward\><<< +while( group_dvi ){ + `<extract backward submissions`> +} +>>> + + +\SubSection{Specials} + +Only \`'~' tex4ht specials are significant here. The ones of the form +\`'\special{t4ht~}' act as end-points for the preprocessing, +and \`'\special{t4ht~<...}' act as backward info delivers. + +\<hooks for backward submissions\><<< +case `<special 1`>: case `<special 2`>: +case `<special 3`>: case `<special 4`>: { long int i; + if( tex4ht_special( &ch, &i ) ){ + if( ch == '~' ){ + `<handle requests for backward submissions`> + } else { + (IGNORED) fseek(dvi_file, (long) i, `<relative file addr`>); + } + }else{ `<ignore non-t4ht special`> } + break; +} +>>> + +\<ignore non-t4ht special\><<< + U_CHAR *ch; +ch = special_hd + 4; +while( *ch ){ ch++; } +(IGNORED) fseek(dvi_file, (long) i, `<relative file addr`>); +>>> + +% while( i-- ) (IGNORED) get_char(); +% change to +% (IGNORED) fseek(dvi_file, (long) i, `<relative file addr`>); +% also in \<chars for idv\> + + +\<handle requests for backward submissions\><<< +if( i==0 ){ + group_dvi = FALSE ; +}else{ + switch( get_char() ){ + case '<': { + if( i-- ){ U_CHAR ch; + if( (ch = get_char()) == '*' ) + { `<send back over token / group`> } + else if( (ch == '[') && (i==1) ){ + i--; `<hide back token / group`> + } + else if( (ch == ']') && (i==1) ){ + i--; `<end hide back token / group`> + } + else if( (ch == '-') && (i==1) ){ + i--; `<latex back token / group`> + } + else if( (ch == '+') && (i==1) ){ + i--; `<end latex back token / group`> + } + else if( (ch == '(') && (i==1) ){ + i--; `<back token / group`> + } + else if( (ch == ')') && (i==1) ){ + i--; `<end back token / group`> + } + else { `<send info back to group open`> } + } + break; } + default: { (IGNORED) fseek(dvi_file, (long) --i, + `<relative file addr`>); break; } +} } +>>> + +% sv_stack_n<stack_n + +When \''sv_stack_n==stack_n' the sending back NEED NOT be in the level +of the opening \''\special{t4ht~}'. This is so because it can happen +that we have, for instance, \`'\special ~<POP><PUSH>' + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Fonts and Default} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +Fonts Definition: + + +\<ignore font def on preview pass\><<< +case `<def 4 byte font`>: (void) get_char(); +case `<def 3 byte font`>: (void) get_char(); +case `<def 2 byte font`>: (void) get_char(); +case `<def 1 byte font`>: { int i; + for( i=14; i; i-- ){ ch = get_char(); } + i = ch + get_char(); + (IGNORED) fseek(dvi_file, (long) i, `<relative file addr`>); + break; } +>>> + +Fonts Activation: + +\<fonts and default ignored on preview pass\><<< +case `<font 1-byte`>: +case `<font 2-bytes`>: +case `<font 3-bytes`>: +case `<font int`>: { + INTEGER n; + n = ch - `<font 1-byte`> + 1; + cr_fnt = (int) ((n==4)? get_int(4) : get_unt((int) n)); + cr_fnt = search_font_tbl( cr_fnt ); + break; } +default: { + if( (ch < `<font 0`>) || (ch > `<font 63`>) ) { + if( ch == `<end page op`> ) { warn_i(46); } + else { warn_i_int(45,ch); } + } else { cr_fnt = ch - `<font 0`>; + cr_fnt = search_font_tbl( cr_fnt ); + } + break; +} +>>> + +\<subp vars\><<< +int cr_fnt; +>>> + +\<init subp vars\><<< +cr_fnt = cur_fnt; +>>> + + + +\SubSection{Skipped Content} + +\<extract backward submissions\><<< +if( (ch = get_char()) >= 128 ) { + switch( ch ){ + `<indirect chars on early backward submissions pass`> + `<ignore font def on preview pass`> + `<ignore on preview pass`> + `<push/pop on backward submissions`> + `<hooks for backward submissions`> + `<fonts and default ignored on preview pass`> + } +} else { `<ch-id + 1`> } +>>> + + + + +\<indirect chars on early backward submissions pass\><<< +case 128: case 129: case 130: case 131: case 133: +case 134: case 135: case 136: { + ch = (int) get_unt( (ch-(ch>132)) % 4 +1); + `<ch-id + 1`> + break; +} +>>> + +\<ignore on preview pass\><<< +case `<insert rule + move op`>: +case `<insert rule + nomove op`>:{ + (IGNORED) fseek(dvi_file, 8L, `<relative file addr`>); + break; +} +>>> + +\<ignore on preview pass\><<< +case `<start page op`>: { + (IGNORED) fseek(dvi_file, 44L, `<relative file addr`>); break; } +>>> + +\<ignore on preview pass\><<< +case `<mv hor 1-byte`>: case `<mv hor 2-byte`>: +case `<mv hor 3-byte`>: case `<mv hor 4-byte`>: { + (IGNORED) (get_int( ch - `<mv hor 1-byte`> + 1 )); break; } +case `<dx.1 store and mv hor 1-byte`>: +case `<dx.1 store and mv hor 2-byte`>: +case `<dx.1 store and mv hor 3-byte`>: +case `<dx.1 store and mv hor 4-byte`>: { + (IGNORED) (get_int( ch - `<dx.1 store and mv hor 1-byte`> + 1)); + break; } +case `<dx.2 store and mv hor 1-byte`>: +case `<dx.2 store and mv hor 2-byte`>: +case `<dx.2 store and mv hor 3-byte`>: +case `<dx.2 store and mv hor 4-byte`>: { + (IGNORED) (get_int( ch - `<dx.2 store and mv hor 1-byte`> + 1)); + break; } +case `<mv ver 1-byte`>: case `<mv ver 2-byte`>: +case `<mv ver 3-byte`>: case `<mv ver 4-byte`>: { + (IGNORED) (get_int( ch - `<mv ver 1-byte`> + 1)); + break; } +case `<dy.1 store and mv ver 1-byte`>: +case `<dy.1 store and mv ver 2-byte`>: +case `<dy.1 store and mv ver 3-byte`>: +case `<dy.1 store and mv ver 4-byte`>: { + (IGNORED) (get_int( ch - `<dy.1 store and mv ver 1-byte`> + 1)); + break; } +case `<dy.2 store and mv ver 1-byte`>: +case `<dy.2 store and mv ver 2-byte`>: +case `<dy.2 store and mv ver 3-byte`>: +case `<dy.2 store and mv ver 4-byte`>: { + (IGNORED) (get_int( ch - `<dy.2 store and mv ver 1-byte`> + 1)); + break; } +>>> + + + +\<ignore on preview pass\><<< +case `<mv hor dist dx.1`>: +case `<mv hor dist dx.2`>: +case `<mv ver dist dy.1`>: +case `<mv ver dist dy.2`>: + { break; } +>>> + + + + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Push/Pop Locations} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<process dvi op 'ch'\><<< +case `<sv loc op`>: { `<push values to stack`> break; } +case `<retrieve loc op`>: { `<pop values from stack`> break; } +>>> + +The dvi stacking code refers to the information \`'x_val', \`'y_val', +\`'dx_1', \`'dx_2', \`'dy_1', and \`'dy_2'. + +\<push values to stack\><<< +`<halign at entry to group`> +`<get backward deliveries`> +stack[stack_n].text_on = text_on; +push_stack(); `<get back sub/sup before group`> +`<path group at entry to group`> +`<trace dvi push`> +`<add push class del`> +>>> + +\<header functions\><<< +static void push_stack( ARG_I(void) ); +>>> + +\<functions\><<< +static void push_stack(MYVOID) +{ + stack[stack_n].x_val = x_val; + stack[stack_n].dx_1 = dx_1; + stack[stack_n].dx_2 = dx_2; + stack[stack_n].y_val = y_val; + stack[stack_n].dy_1 = dy_1; + stack[stack_n].dy_2 = dy_2; + `<push inherit del`> + stack_n++; +if( stack_n > `<size of stack for nested boxes`> ){ + warn_i(40); +} + `<init end math accented`> +} +>>> + +\<push inherit del\><<< +stack[stack_n+1].sv_no_left_del = stack[stack_n+1].no_left_del; +stack[stack_n+1].no_left_del = stack[stack_n].no_left_del; +>>> + +\<pop uninherit del\><<< +stack[stack_n].no_left_del = stack[stack_n].sv_no_left_del; +>>> + + +The first statement partially handles spaces after text that is inserterted +to the left of the current location (e.g., items of list). + +\<pop values from stack\><<< +`<add pop class del`> +`<path group at exit from group`> +`<get forward deliveries`> +`<trace dvi pop`> +`<halign at exit from group`> +pop_stack(); +if( ((x_val+0.6*word_sp) < stack[stack_n].x_val) ) put_char(' '); +text_on = stack[stack_n].text_on; +>>> + + +\<header functions\><<< +static void pop_stack( ARG_I(void) ); +>>> + +\<functions\><<< +static void pop_stack(MYVOID) +{ + `<end math accented`> + `<pop uninherit del`> + --stack_n; + x_val = stack[stack_n].x_val; + dx_1 = stack[stack_n].dx_1; + dx_2 = stack[stack_n].dx_2; + y_val = stack[stack_n].y_val; + dy_1 = stack[stack_n].dy_1; + dy_2 = stack[stack_n].dy_2; +} +>>> + + + + +\Section{Backward Token / Group Submissions} + +TeX places subscripts and superscripts on the most recent group or +token. We are looking where the most recent of these tokens starts, +and store there the desired info. + +% \`'\special{...[}...\special{...]}' is ignore when looking for +% tokens. \`'\special{...]...}' sends back its content to the start of +% the most recent entity. \`'\special{...[*...*...}' sets open-close +% math codes---how? + + +\SubSection{Scan to Record Recieving Points} + +We keep a delimiter stack for the parenthesis, and include there also +the opening and closing of groups. The latter one are employed +to deal with parenthese that are not balanced, for instance, +\`'\left( ... \right.'. + +\<pop-id + 1\><<< +if( !back_id_off ){ + if( !id_hide ){ ch_token = FALSE; + sv_id = stack[stack_n].stack_id; } + while( del_stack != (struct del_stack_entry*) 0 ){ + struct del_stack_entry* p; + int id; + del_stack = (p = del_stack)->next; + id = p->id; + free((void *) p ); + if( id == -1 ) break; +} } +>>> + +\<push-id + 1\><<< +if( !back_id_off ) +{ struct del_stack_entry *p; + p = m_alloc(struct del_stack_entry,1); + p->next = del_stack; + p->id = p->fnt = -1; + del_stack = p; +} +>>> + + + + + + +\<ch-id + 1\><<< +ch_id++; +if(!back_id_off ){ + if( !id_hide ){ ch_token = TRUE; sv_id = ch_id; } + switch( math_class_of( ch, cr_fnt ) ){ + case `<math open`>: { del_stack = push_del( (char) ch, cr_fnt); + break; } + case `<math close`>: { + del_stack = pop_del( (char) ch, id_hide, cr_fnt); break; } + default:{ ; } +} } +>>> + + + +\<math close\><<< +5 +>>> + +\<math open\><<< +4 +>>> + + + + +Assumption made: closing del is in the same font as the opening one. + + + + +\<header functions\><<< +static struct del_stack_entry* push_del( ARG_II(char, int) ); +>>> + +\<functions\><<< +`[ +static struct del_stack_entry* push_del(ch, cr_fnt) U_CHAR ch`; + int cr_fnt +;{ struct del_stack_entry *p; + p = m_alloc(struct del_stack_entry,1); + p->next = del_stack; + p->ch = ch; + p->fnt = cr_fnt; + p->id = ch_id; + return p; +} +>>> + + + + +\<header functions\><<< +static struct del_stack_entry* pop_del( ARG_III(char,int,int) ); +>>> + +\<functions\><<< +`[ +static struct del_stack_entry* pop_del(ch, id_hide, cr_fnt) + U_CHAR ch`; + int id_hide`; + int cr_fnt +;{ + if( del_stack != (struct del_stack_entry*) 0 ){ + if( (cr_fnt == del_stack->fnt) && + ( *(font_tbl[cr_fnt].math + (ch - font_tbl[cr_fnt].char_f)) + == del_stack->ch) ){ + struct del_stack_entry * p; + if( !id_hide && !id_latex ){ sv_id = del_stack->id; } + del_stack = (p = del_stack)->next; free((void *) p ); + } } + return del_stack; +} +>>> + + +What the \''id_latex' does here? + + + + +\<vars\><<< +static struct del_stack_entry *del_stack; +>>> + +\<main's init\><<< +del_stack = (struct del_stack_entry *) 0; +>>> + + +\<types\><<< +struct del_stack_entry{ + struct del_stack_entry *next; + U_CHAR ch; + int fnt, id; +}; +>>> + + + + + + + + + +\<vars\><<< +static int ch_id, sv_id, id_latex, back_id_off; +>>> + +\<main's init\><<< +back_id_off = 1; id_latex = 0; +>>> + + + +\<init ch-id\><<< +ch_id = 0; +>>> + +\<subp vars\><<< +BOOL ch_token; +int id_hide; +>>> + +\<init subp vars\><<< +sv_id = 0; `<init ch-id`> +id_hide = 0; ch_token = TRUE; +while( del_stack != (struct del_stack_entry*) 0 ){ + struct del_stack_entry* p; + del_stack = (p = del_stack)->next; + free((void *) p ); +} +>>> + + + + + +\<hide back token / group\><<< +id_hide++; +>>> + + +\<end hide back token / group\><<< +id_hide--; +>>> + +\<latex back token / group\><<< +id_latex++; +>>> + + +\<end latex back token / group\><<< +id_latex--; +>>> + + + +\<back token / group\><<< +back_id_off++; +>>> + + +\<end back token / group\><<< +back_id_off--; +>>> + + + + + + + +\SubSection{Memory for Linked Lists} + +\<types\><<< +struct send_back_entry{ + struct send_back_entry *next; + U_CHAR *send; + int id; +}; +>>> + + +\<vars\><<< +static struct send_back_entry *back_token, *back_group; +>>> + +\<main's init\><<< +back_token = back_group = m_alloc(struct send_back_entry,1); +back_token->id = -1; +>>> + + + +\SubSection{Scan Backward Submissions} + + + +\<send back over token / group\><<< + struct send_back_entry *p, *q, *t=0; +if( back_id_off ){ + while( i-- ){ (IGNORED) get_char(); } +} else { + p = m_alloc(struct send_back_entry,1); + p->send = get_str( (int)( i - 1 )); + if( ch_token ){ + `<send back to char`> + } else { + p->id = (sv_id<0? 0 : sv_id) + push_id; + if( back_group->id < p->id ) + { p->next = back_group; back_group = p; } + else + { q = back_group; + while( q->id >= p->id ) { t = q; q = q->next; } + p->next = t->next; t->next = p; + } + } +} +>>> + + +Keep \ifHtml[\HPage{consistency}\Verbatim + +$ +a +\Send{BACK}{1} +\Send{BACK}{2} +\Send{BACK}{3} +\Send{BACK}{4} +\hbox{ab} +\Send{BACK}{1} +\Send{BACK}{2} +\Send{BACK}{3} +\Send{BACK}{4} +$ + +produce 4321a4321ab +\EndVerbatim\EndHPage{}]\fi{} between back on group and back on token + +\<send back to char\><<< +p->id = sv_id; +if( sv_id > back_token->id ){ + p->next = back_token; back_token = p; +} else { + q = back_token; + while( sv_id <= q->id ){ t = q; q = q->next; } + p->next = t->next; t->next = p; +} +>>> + +The following reverses the linked lists for ids and groups, so that +the early entries will get at the head instead of the tail. + + +\<exit early pass\><<< +back_group = rev_list( back_group ); +back_token = rev_list( back_token ); +back_token = back_insert ( back_token, 0); +`<init ch-id`> +>>> + + +\<header functions\><<< +static +struct send_back_entry * rev_list( ARG_I(struct send_back_entry *) ); +>>> + +\<functions\><<< +`[ +static struct send_back_entry * rev_list(back_group) + struct send_back_entry *back_group +;{ struct send_back_entry *p, *q, *t; + if( back_group->id == -1 ){ return back_group; } + p = back_group; q = p->next; + while( p->id != -1 ){ + t = q->next; q->next = p; p = q; q = t; + } + back_group->next = p; + return p->next; +} +>>> + + + + +\SubSection{Use Backward Submissions} + + + + + +\<get back sub/sup before group\><<< +if( group_dvi ) { + back_group = back_insert ( back_group, push_id); +} +>>> + + + +\<get back sub/sup before ch\><<< +if( group_dvi ){ + if( ( ch < 132 ) || + ( (ch > 127) && (ch < 137) && (ch != `<insert rule + move op`> ) ) + ){ + ch_id++; + back_token = back_insert ( back_token, ch_id); +} } +>>> + + + + + + + + +\<header functions\><<< +static struct send_back_entry * + back_insert( ARG_II(struct send_back_entry *, int) ); +>>> + +\<functions\><<< +`[ +static struct send_back_entry * back_insert(back, id) + struct send_back_entry *back`; + int id +;{ + while( back->id == id ){ + struct send_back_entry *p; + print_f( back->send ); + back = (p = back)->next; + free((void *) p->send ); + free((void *) p ); + } + return back; +} +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Actions on Forward Groups Accessed Through Pathes} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Motivation} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +The current instructions are motivated by the \`'\sqrt' structure + +\Verbatim +PUSH + PUSH + ......sqrt et al symbols, possibly with PUSH-POP...... + POP + PUSH + W3: 655361 + DOWN3: -1020474 + PUT_RULE: height: 26213 + length: 1091179 + DOWN3: 1020474 + PUSH + .....body......... + POP + POP +POP +\EndVerbatim + +and the \`'\root ...\of {...}' construct + +\Verbatim +PUSH + ...root value... +POP +PUSH + PUSH + PUSH + ...root sign characters with PUSH-POP... + POP + PUSH + RIGHT4: 15213546 + DOWN3: -1553322 + PUT_RULE: height: 26213 + length: 1197667 + DOWN3: 1553322 + PUSH + ...root content... + POP + POP + POP +POP +\EndVerbatim + +For instance, + +\Verbatim +$ +\special{t4ht\string~} +\special{t4ht=<msqrt>} +%%%%%%%% +\special{t4ht\string~!e<[BEFORE]} % insert at start of path +\special{t4ht\string~!e>[AFTER]} % insert at end of path +\special{t4ht\string~!ee/} % ignore content within group +\special{t4ht\string~!ese-} % ignore until rulers until next group +%%%%%% +\sqrt 1 +\special{t4ht\string~} +$ + +$ +\special{t4ht\string~}% +\special{t4ht=<mroot>}% +%%%%%%%% +\special{t4ht\string~!see<[BEFORE]} +\special{t4ht\string~!see>[AFTER]} +\special{t4ht\string~!seee/} +\special{t4ht\string~!seese-} +%%%%%% +\root 2\of 3% +\special{t4ht\string~} +$ +\EndVerbatim + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Record Request} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + + +\<struct stack_entry\><<< +struct group_path * path_start, * path_end; +>>> + + +\<types\><<< +struct group_path{ + U_CHAR action; + U_CHAR *path; + U_CHAR *info; + struct group_path * next; +}; +>>> + + +\<initialized entries for grouping stack\><<< +stack[i].path_start = (struct group_path *) 0; +stack[i].path_end = (struct group_path *) 0; +>>> + +\<store path-based forward submissions\><<< + struct group_path *p, *t; + U_CHAR *q, str[256]; + int n; +p = m_alloc(struct group_path,1); +`<record action and path`> +`<record info for path`> +n = stack_n - 1; +if( p->action == '>' ){ + p->next = stack[ n ].path_end; + stack[ n ].path_end = p; +} else { + p->next = (struct group_path *) 0; + if( stack[n].path_start == (struct group_path *) 0 ) { + stack[n].path_start = p; + } else { + t = stack[n].path_start; + while( t->next != (struct group_path *) 0 ) { t = t->next; } + t->next = p; +} } +>>> + + +\<record action and path\><<< +n = 0; +while( --special_n ) { + str[n] = get_char(); + if( ( str[n] != 'e') && (str[n] != 's') ){ break; } + n++; +} +if(( + ( str[n] != '<') && (str[n] != '>') && + ( str[n] != '/') && (str[n] != '-') + ) || (n==0) ){ + str[n+1] = '\0'; + err_i_str(38,str); +} +p->action = str[n]; str[n] = '\0'; +p->path = m_alloc(char,n+1); +(IGNORED) strcpy((char *) p->path, (char *) str); +>>> + +\<record info for path\><<< +q = p->info = m_alloc(char,special_n+1); +while( --special_n ) *q++ = get_char(); +*q = '\0'; +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Process Path Lists At Entry To Group} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<path group at entry to group\><<< +{ + `<vars for path processing`> + if( `<radical-line-off`> ){ + `<end ignore spaces`> + `<radical-line-off`> = FALSE; + } + if( stack_n > 1 ){ + p = stack[stack_n - 2].path_start; + if( p != (struct group_path *) 0 ){ + `<traverse path starts on entry`> + } + p = stack[stack_n - 2].path_end; + if( p != (struct group_path *) 0 ){ + `<traverse path ends on entry`> + } + `<connect the revised path lists`> +} } +>>> + +\<vars for path processing\><<< +struct group_path *start_head, *start_tail, + *parent_start_head, *parent_start_tail, + *end_head, *end_tail, + *parent_end_head, *parent_end_tail, + *p, *q; +int place=0; +start_head = start_tail = parent_start_head = parent_start_tail + = end_head = end_tail = parent_end_head + = parent_end_tail = (struct group_path *) 0; +>>> + +\<connect the revised path lists\><<< + stack[stack_n - 1].path_start = start_head; + stack[stack_n - 1].path_end = end_head; + stack[stack_n - 2].path_start = parent_start_head; + stack[stack_n - 2].path_end = parent_end_head; +>>> + + + +\<traverse path starts on entry\><<< +while( p != (struct group_path *) 0 ){ + `<process a path-start at entry`> + q = p; + p = p->next; + q->next = (struct group_path *) 0; + `<update temporary start paths`> +} +>>> + +\<traverse path ends on entry\><<< +while( p != (struct group_path *) 0 ){ + `<process a path-end at entry`> + q = p; + p = p->next; + q->next = (struct group_path *) 0; + `<update temporary end paths`> +} +>>> + +\<update temporary start paths\><<< +switch( place ){ + case `<store at parent path-start`>: + if( parent_start_head == (struct group_path *) 0 ){ + parent_start_head = parent_start_tail = q; + } else { + parent_start_tail = parent_start_tail->next = q; + } + break; + case `<store at path-start`>: + if( start_head == (struct group_path *) 0 ){ + start_head = start_tail = q; + } else { + start_tail = start_tail->next = q; + } + break; + case `<delete path entry`>: + `<delete path entry q`> + break; +} +>>> + +\<update temporary end paths\><<< +switch( place ){ + case `<store at parent path-end`>: + if( parent_end_head == (struct group_path *) 0 ){ + parent_end_head = parent_end_tail = q; + } else { + parent_end_tail = parent_end_tail->next = q; + } + break; + case `<store at path-end`>: + if( end_head == (struct group_path *) 0 ){ + end_head = end_tail = q; + } else { + end_tail = end_tail->next = q; + } + break; + case `<delete path entry`>: + `<delete path entry q`> + break; +} +>>> + +\<store at parent path-start\><<< +0 >>> + +\<store at parent path-end\><<< +1 >>> + +\<store at path-start\><<< +2 >>> + +\<store at path-end\><<< +3 >>> + +\<delete path entry\><<< +4 >>> + +\<delete path entry q\><<< +free((void *) q->path ); +free((void *) q->info ); +free((void *) q ); +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Process Individual Records at Entry To Group} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +The `e' records at the parent's path-start are moved to the path-start +list of the current group, with the leading `e' removed from the path. +The only exception is for paths of length 1 with actions \`'<' and +\`'-'. They contribute their content to the output, and then +discarded. + +The `s' records at the parent's path-start list stay at that list, +with the `s' character removed from the path. + + +The other records remain at the parent path-start list, to be removed +at the end of that group. + +\<process a path-start at entry\><<< +if( *(p->path ) == 'e' ) { + (IGNORED) strcpy((char *) p->path, (char *) p->path+1); + if( *(p->path) == '\0' ) { + switch( p->action ){ + case '<': print_f( p->info ); + place = `<delete path entry`>; + break; + case '/': ignore_chs++; + place = `<store at path-start`>; break; + case '-': `<radical-line-off`> = TRUE; + `<ignore spaces`> + place = `<delete path entry`>; break; + } + } else { + place = `<store at path-start`>; + } +} else { + if( *(p->path ) == 's' ) { + (IGNORED) strcpy((char *) p->path, (char *) p->path+1); + } + place = `<store at parent path-start`>; +} +>>> + + +The `s' records at the parent's path-end list stay at that list, +with the `s' character removed from the path. + +The `e' records are moved to the path-end list of the current group, +with the leading `e' removed from the path. + +The other records are left intact at the parent's path-end list. + + + +\<process a path-end at entry\><<< +if( *(p->path ) == 'e' ) { + (IGNORED) strcpy((char *) p->path, (char *) p->path+1); + place = `<store at path-end`>; +} else { + if( *(p->path ) == 's' ) { + (IGNORED) strcpy((char *) p->path, (char *) p->path+1); + } + place = `<store at parent path-end`>; +} +>>> + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Path Group At Exit From Group} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<path group at exit from group\><<< +{ + struct group_path *p, *q; + if( stack_n > 1 ){ + p = stack[stack_n - 1].path_start; + if( p != (struct group_path *) 0 ){ + `<traverse path starts on exit`> + } + p = stack[stack_n - 1].path_end; + if( p != (struct group_path *) 0 ){ + `<traverse path ends on exit`> +} } } +>>> + + +\<traverse path starts on exit\><<< +while( p != (struct group_path *) 0 ){ + `<process a path-start at exit`> + q = p; + p = p->next; + `<delete path entry q`> +} +>>> + +\<traverse path ends on exit\><<< +while( p != (struct group_path *) 0 ){ + `<process a path-end at exit`> + q = p; + p = p->next; + `<delete path entry q`> +} +>>> + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Process Individual Records at Exit from Group} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<process a path-start at exit\><<< +if( *(p->path) != '\0' ) { + `<warn 38 for path`> +} else { + switch( p->action ){ + case '/': ignore_chs--; break; + default: { + `<warn 38 for path`> + break; +} } } +>>> + + + + + +\<process a path-end at exit\><<< +if( *(p->path) != '\0' ) { + `<warn 38 for path`> +} else { + switch( p->action ){ + case '>': print_f( p->info ); break; + default: { + `<warn 38 for path`> + break; +} } } +>>> + + + +\<warn 38 for path\><<< + char str[256]; +(IGNORED) strcpy(str, "...."); *(str+3) = p->action; +(IGNORED) strct(str,p->info); warn_i_str(38,str); +>>> + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Chapter{Position-Based Decoration} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\Section{Background} + +We assume a rectangualar canvase for which we can provide the +measurements, as well as the location of each character and ruler in it. + +A region starts and ends with a \`'\special{t4ht"}'. The entry point +gets coordinates (0,0). It is configured +wuth + +\Verbatim +\special{t4ht"% + * before-all + * after-all %right %left %height %depth + ............. + ** before-char %x %y + * after-char + * line %x %y %thickness %length + * x-coefficients: A-magnification, B-displacement %A(x) + %B + * y-coefficients: C-magnification, D-displacement, E/F-origin + %C(y + (%E(up) | %F(height+depth)) ) + %D + } +\EndVerbatim + +The \`'*' is a seperator character, and it can be replaced by other +characters. + +We assume C-type templates, where values are assumed to be in float +decimals (e.g., \`'%.2f'; replacing 2 by 0, implies an integer). + +The \`'* after-all' can be repeated arbitrary many times (must appear +at least once). The last one is found when \`'**' is encountered. + +The first character in each \`'after-all' is treated as a code: x-min +x, X-max x, y-min , Y-max y, w-dx, h-dy, otherwise-string with no +value. We need the codes to enable arbitrary combinations of values. + +The \`'before-char' must be non-empty for \`'%x %y' to be printed. +The case is similar for the ruler. If both are empty, we just +measure the dvi dimensions--can be used for applets. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Compute Character Position} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<pos dvi ch\><<< +if( pos_dvi ){ long int d; + if( *pos_text ){ + `<open output file`> + (IGNORED) fprintf(cur_o_file, pos_text, + pos_x_A * (x_val - base_pos_x) + pos_x_B, + pos_y_C * (y_val - base_pos_y) + pos_y_D); + } + if( x_val < min_pos_x ) min_pos_x = x_val; + if( (d = x_val + `<ch width`>) > max_pos_x ) max_pos_x = d; + if( (d = y_val - `<ch height`>) < min_pos_y ) min_pos_y = d; + if( (d = y_val + `<ch depth`>) > max_pos_y ) max_pos_y = d; +} +>>> + + +% pos_y_D * (`<(double) char_height( ch )`> - base_pos_h) + + + +\<end pos dvi ch\><<< +if( pos_dvi ){ + print_f(end_pos_text); +} +>>> + + +\ifHtml[\HPage{more}\Verbatim + \ifx \documentclass\undef \else +\documentclass{book} + \fi +\input DraTex.sty \input AlDraTex.sty + + +\input tex4ht.sty \Preamble{html,sty,4.0s} + \ifx \documentclass\undef \else +\begin{document} + \fi + + + +\ScriptCommand{\CssFile}{\HCode{<STYLE>\EolnCh}}{\HCode{</STYLE>}} + +\CssFile + BODY{ font-size : 200% } + .canvas { position: relative; } + SPAN.cmr-7 .char , + SPAN.cmmi-7 .char , + SPAN.cmsy-7 .char { font-size: 70% ; } + SPAN.cmr-5 .char , + SPAN.cmmi-5 .char { font-size: 50% ; } +\EndCssFile + + + \EndPreamble % \Validate{temp/\jobname.html} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + + +\special{t4ht"*<SPAN\EolnCh + CLASS="canvas">*<SPAN STYLE="position:relative;\EolnCh + width:\%.2fex"></SPAN></SPAN>*<SPAN\EolnCh + STYLE="position:absolute; left:\%.2fex; + top:\%.2fex"\EolnCh + CLASS="xy"><SPAN\EolnCh CLASS="char">*</SPAN></SPAN>*<SPAN top="\%.2f" + left="\%.2f" CLASS="xy">*</SPAN>*0.00000290646*0.0*0.00000290646*0.0*0.5} + +aa +\special{t4ht"}$ +\SUBSUPOff +\let\Picture=\empty +..\qquad...............a^{c^1}_{b_2}a^c_bccccc...c +$\special{t4ht"}XX + + +aa +\special{t4ht"}$ +\SUBSUPOff +\let\Picture=\empty +{A+C \over B+D}+F \over X*Y +$\special{t4ht"}........... + + + +x + +\end{document} + +1ex = 344061 + +Addresses in dvi are on baseline. The same is true for +positioned text in html. That is, +the point of reference of the printed character is placed at +the specified position (\ifHtml[\HPage{margin}\Verbatim +<DIV STYLE="position:absolute; + left:100; top:50;"> + (/\/\/\/\/\) + </DIV> + +<DIV STYLE="position:absolute; + left:100; top:50;"> + ........................ + </DIV> +\EndVerbatim\EndHPage{}]\fi). + + +\ifHtml[\HPage{?}\Verbatim +Positioning of characters? + +The attached source tries three renderings for `A<sub>x</sub>'. My +understanding of the positioning mechanism is that, in all three cases, +the reference point for `x' should be 0.7ex under the right leg of A. +Moreover, the measurement 0.7ex should be with respect to the +dimension of the font of A. + + /\ + /--\ + / \........... + \/ } 0.7ex within font of A + ./\.......} + +Is that understanding correct? + +NN 4.04 provides the desired outcome in the first case, but not in the +second and third cases. IE 4.0, on the other hand, produces the +desired outcome for the second and the third cases, but not the first. + +-eitan + + +<HTML><HEAD> <TITLE>aa.html</TITLE> </HEAD><BODY> +<P> A<SPAN +STYLE="position:relative"><SPAN +STYLE="position:absolute; top:0.7ex"><SPAN +STYLE="font-size: 70% ;">x</SPAN></SPAN></SPAN> + +<P> A<SPAN +STYLE="position:relative"><SPAN +STYLE="position:relative; top:0.7ex"><SPAN +STYLE="font-size: 70% ;">x</SPAN></SPAN></SPAN> + +<P> A<SPAN +STYLE="position:relative"><SPAN +STYLE="position:absolute; top:0.7ex"><SPAN +STYLE="font-size: 100% ;">x</SPAN></SPAN></SPAN> + +<P> y +</BODY></HTML> + +\EndVerbatim\EndHPage{}]\fi + + + +\Section{Compute Ruler Position} + + +\<pos dvi x rule\><<< + long int d; +if( (up > 0) && (right > 0) ){ + if( *pos_line ){ + double from_x, from_y; + `<open output file`> + from_x = pos_x_A * (x_val - base_pos_x) + pos_x_B; + from_y = pos_y_C * (y_val - pos_y_E * up - base_pos_y) + pos_y_D; + switch (rect_pos){ + case 1: { + (IGNORED) fprintf(cur_o_file, pos_line, + from_x, from_y, + pos_x_A * right + pos_x_B + from_x, + pos_y_C * up + pos_y_D + from_y ); + break; } + case 2: { + (IGNORED) fprintf(cur_o_file, pos_line, + from_x, from_y, + pos_x_A * right + pos_x_B + from_x, + from_y, + pos_y_C * up + pos_y_D ); + break; } + default: { + (IGNORED) fprintf(cur_o_file, pos_line, + from_x, from_y, + pos_x_A * right, + pos_y_C * up); + } + } + } + if( x_val < min_pos_x ) min_pos_x = x_val; + if( (d = x_val + right) > max_pos_x ) max_pos_x = d; + if( (d = y_val - up) < min_pos_y ) min_pos_y = d; + if( y_val > max_pos_y ) max_pos_y = y_val; +} +>>> + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Boundary Conditions} +%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<positioned content\><<< +if( special_n ){ + `<read pos instructions`> +} else if( (pos_dvi = !pos_dvi) == TRUE ){ + print_f(pos_body); + min_pos_x = max_pos_x = base_pos_x = x_val; + min_pos_y = max_pos_y = base_pos_y = y_val ; +} else { U_CHAR *p; + double dim=0.0; + BOOL dim_on; + `<open output file`> + p = end_pos_body; + while( *p ){ + dim_on = TRUE; + switch( *p ){ + `<dim = pos value`> + default: { dim_on = FALSE; } + } + p++; + if( dim_on ){ (IGNORED) fprintf(cur_o_file, p, dim); } + else { (IGNORED) fprintf(cur_o_file, "%s", p); } + while( * (p++) ); + } +} +>>> + +The pattern of of \`'end_pos_body' has a \`'\0' at the end +of each segment, and the last segment is empty. Hence, it +ends with a \`'\0\0'. + +\<dim = pos value\><<< +case 'X': { dim = pos_x_A * (max_pos_x - base_pos_x) + pos_x_B; + break; } +case 'x': { dim = pos_x_A * (base_pos_x - min_pos_x) + pos_x_B; + break; } +case 'd': { dim = pos_x_A * (max_pos_x - min_pos_x) + pos_x_B; + break; } +case 'y': { dim = pos_y_C * (base_pos_y - min_pos_y - 1) + pos_y_D; + break; } +case 'Y': { dim = pos_y_C * (max_pos_y - base_pos_y) + pos_y_D; + break; } +case 'D': { dim = pos_y_C * (max_pos_y - min_pos_y) + pos_y_D; + break; } +>>> + + +\<vars\><<< +static BOOL pos_dvi = FALSE; +static U_CHAR *pos_body, * pos_text, * pos_line, + *end_pos_body, * end_pos_text; +static double pos_x_A, pos_x_B, pos_y_C, pos_y_D, pos_y_E; +static long int base_pos_x, base_pos_y, min_pos_x, + max_pos_x, min_pos_y, max_pos_y; +static short rect_pos; +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Scan Coefficients} +%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Note that \`'pos_body' points to the left-most byte in the template. + + +\<main's init\><<< +pos_text = pos_line = end_pos_body = end_pos_text = pos_body = + m_alloc(char, (int) 1); +(IGNORED) strcpy((char *) pos_text, "" ); +>>> + + +\<read pos instructions\><<< +{ U_CHAR * p, ch, i; + ch = get_char(); + p = pos_text = pos_line = end_pos_text + = end_pos_body = pos_body + = (char *) r_alloc((void *) pos_body,(size_t) special_n + 1); + i = 0; `<scan templates for pos`> + `<scan constants for pos`> + if( (i != 10) || special_n ){ + warn_i_str(39,pos_text); + *(pos_text = end_pos_body = pos_line = + end_pos_text = pos_body) = '\0'; + } +} +>>> + + + + +\<scan templates for pos\><<< +{ BOOL after_star=0; + while( special_n-- > 0 ){ + if( (*p = get_char()) == ch ){ + *p = '\0'; i++; + if( i==1 ){ end_pos_body = p + 1; after_star = FALSE; } + else if( i==2 ){ pos_text = p + 1; + if( !after_star ){ i--; after_star = TRUE; } + } + else if( i==3 ){ end_pos_text = p + 1; } + else if( i==4 ){ pos_line = p + 1; } + else { p++; break; } + } else { after_star = FALSE; } + p++; + } +} +>>> + + + +\<scan constants for pos\><<< +{ long int v=0; + double w[5]; + int j; + U_CHAR ch, sign; + BOOL done; + for(j=0;j<5;j++){ + `<v = int part; sign = ...`> + if( done ){ + i++; + w[j] = sign * ((double) v + pos_dbl( &special_n )); + } + } + pos_x_A = w[0]; pos_x_B = w[1]; + pos_y_C = w[2]; pos_y_D = w[3]; pos_y_E = w[4]; +} +rect_pos = (special_n == 2); +if( rect_pos ){ special_n -= 2; rect_pos = get_char() - '0';} +>>> + + + +\<v = int part; sign = ...\><<< +done = FALSE; sign = 1; +if( --special_n > 0 ){ + if( (ch = get_char()) == '-' ){ sign = -1; v=0; } + else v = ch - '0'; + if( (v<0) || (v>9) ) done = TRUE; +} +if( !done ) + while( --special_n > 0 ){ + ch = get_char(); + if( ('0' <= ch ) && (ch <= '9' ) ){ + v = v * 10 + ch - '0'; } + else{ done = TRUE; break; } + } +>>> + + + +\<header functions\><<< +static double pos_dbl( ARG_I(long int *) ); +>>> + +\<functions\><<< +`[ +static double pos_dbl( special_n ) long int * special_n +;{ + U_CHAR ch; + double v; + int d; + v = 0.0; d = 10; + while( --(*special_n) > 0 ){ + ch = get_char(); + if( ('0' <= ch ) && (ch <= '9' ) ){ + v += (double) (ch -'0') / d; d *= 10; } + else break; + } + return v; +} +>>> + + + +\<err int pos\><<< +123454321 +>>> + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Chapter{Font Information from TeX Font Metric (tfm) Files} +%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Managed by load-font (\LinkPort\<font 0\>font 0\EndLink +--\LinkPort\<font 63\>font 63\EndLink, +\LinkPort\<font 1-byte\>font 1-byte\EndLink +--\LinkPort\<font int\>font int\EndLink) and activate-font +(\LinkPort\<def 1 byte font\>def 1-byte font\EndLink +--\LinkPort\<def 4 byte font\>def 4 byte font\EndLink) commands. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Memory and Initialization} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +A font def looks like: \Link{}{fntdef} \EndLink{} + +\Verbatim +FNT_DEF1...FNT_DEF4 + 1,2,3 ubytes or 4 bytes font number + 4 ubytes checksum + 4 ubytes scale + 4 ubytes design size + 1 byte length of directory name + 1 byte length of file name + dir-ln + file-ln bytes fontname +\EndVerbatim + +Checksums are used to verify consistency between tfm and gf font files. + + + +\Verbatim +000284: FNT_DEF1: 29 +000286: checksum : -538297224 +000290: scale : 655360 +000294: design : 655360 +000298: name : cmtt10 +000306: FNT_DEF1: .... +\EndVerbatim + + +\<types\><<< +struct font_entry { + INTEGER num; + INTEGER scale; + INTEGER design_sz; + `<mag of font`> + `<family+size of font`> + `<entries from font file into font-tbl`> + `<entries for html chars in font-tbl`> + `<entries for math classes`> + `<entries for xetex`> +}; +>>> + + + +\<defines\><<< +#define design_size_to_pt(n) ((double)n / (double)(1L<<20)) +>>> + +\<vars\><<< +static struct font_entry* font_tbl; +static int font_tbl_size = 0; +>>> + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Storage for New Font} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +The standard fonts of Knuth have design size of 0x90000 for fonts of +size 9, 0xa0000 for size 10, etc. + + +% INTEGER `%, new_font_dir`% + + + + + +\<scan font entry\><<< +#ifdef MAXFONTS +if( (font_tbl_size + 1) < MAXFONTS ) +#endif +{ + INTEGER new_font_checksum; + int font_name_n; + font_tbl = font_tbl_size? + (struct font_entry *) r_alloc((void *) font_tbl, + (size_t) ((font_tbl_size+1) + * sizeof(struct font_entry))) + : m_alloc(struct font_entry, 1); + if( (version_id == `<version xdv`>) + && (ch == `<xdv-native-font-def op`>) + ){ + `<scan xdv font entry`> + } else { + `<scan dvi font entry`> + } + `<get html characters`> + `<get css entries`> + free((void *) new_font_name); font_tbl_size++; +} +#ifdef MAXFONTS + else err_i_int(17, MAXFONTS); +#endif +>>> + + + + + + + +\<scan dvi font entry\><<< +`<scan font id`> +new_font_checksum = (INTEGER) get_int(4); +new_font.scale = (INTEGER) get_unt(4); +new_font.design_sz = (INTEGER) get_unt(4); +`<get font name`> +`<get font info`> +>>> + + + + +\<vars\><<< +static char* new_font_name; +>>> + + + +\<defines\><<< +#define new_font font_tbl[font_tbl_size] +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Get Data} +%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<scan font id\><<< +switch( ch ){ + case `<def 1 byte font`>: + case `<def 2 byte font`>: + case `<def 3 byte font`>: { + new_font.num = (INTEGER) + get_unt(ch - `<def 1 byte font`> + 1); break; } + case `<def 4 byte font`>: { + new_font.num = (INTEGER) get_int(4); break; } + default: err_i(8); +} +>>> + + +\<get font name\><<< +{ int n, area_ln; + U_CHAR *ch; + area_ln = (int) get_unt(1); + font_name_n = (int) get_unt(1); + n = area_ln + font_name_n + 1; + ch = new_font_name = m_alloc(char, n); + while( --n ){ *ch = (int) get_unt(1); ch++; } + *ch = '\0'; +} +>>> + + + + + +\<get font info\><<< +`<first definition of font?`> +`<open font file`> +new_font_name[font_name_n] = '\0'; +new_font.name = m_alloc(char, font_name_n + 1); +(IGNORED) strcpy((char *) new_font.name, (char *) new_font_name ); +`<family and size of font`> +`<compute mag of font`> +>>> + + +The following is computed from \`'scale' and \`'design_sz'. +We take it here relative to 100. + + +\<compute mag of font\><<< +new_font.mag = new_font.scale / (new_font.design_sz / 100); +>>> + +\<mag of font\><<< +INTEGER mag; +>>> + +\<family+size of font\><<< +char *family_name, *font_size; +>>> + + +\<family and size of font\><<< +{ int n, i; + for( n=0; n<font_name_n; n++ ){ + if( ( '0' <= new_font_name[n] ) && ( new_font_name[n] <= '9' )){ + break; + } + } + `<real size?`> + new_font.family_name = m_alloc(char, n + 2); + new_font.font_size = m_alloc(char, font_name_n - n + 1 ); + for( i=0; i<n; i++ ){ + new_font.family_name[i] = new_font_name[i]; + } + new_font.family_name[i] = '\0'; i = 0; + while( n<font_name_n ){ + new_font.font_size[i++] = new_font_name[n++]; + } + new_font.font_size[i] = '\0'; +} +>>> + + +\<real size?\><<< +{ int m; + for( m=n; m<font_name_n; m++ ){ + if( ( new_font_name[m] < '0' ) || ( new_font_name[m] > '9' )){ + n=font_name_n; + break; +} } } +>>> + + +When the size is not zero, n+2 can be reduced to n+1. + +\<output to lg file\><<< +(IGNORED) fprintf(log_file, lg_font_fmt, + font_tbl[cur_fnt].family_name, + font_tbl[cur_fnt].font_size, + (int)( font_tbl[cur_fnt].design_sz * 100 / 655360 / 10), + font_tbl[cur_fnt].mag); +>>> + + +Fosome font names (e.g., Chinese: gbkhei65) we don't want the number to +be treated as font-size: + +\<check name decomposition\><<< +if( (strlen((char *) new_font.family_name) + + strlen((char *) new_font.font_size) + 4) == strlen((char *) name) ){ + new_font.family_name = (char *) r_alloc((void *) new_font.family_name, + (size_t) (strlen((char *) name)+1)); + (IGNORED) strcat((char *) new_font.family_name, (char *) new_font.font_size); + *(new_font.font_size)='\0'; +} +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Script lg-font-fmt} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +Font information to decorate characters, e.g., for style files. + +\<h-defines\><<< +#ifndef LGFNT +#define LGFNT "Font(\"%s\",\"%s\",\"%d\",\"%d\")\n" +#endif +>>> + + +\<vars\><<< +static U_CHAR *lg_font_fmt = NULL; +>>> + + + +\<get from tex4ht.env file\><<< +lg_font_fmt = (char *) get_script(lg_font_fmt,LGFNT,'f'); +>>> + + + + +%%%%%%%%%%%%% +\Section{XeLaTeX: Scan Xdv Font Entry (Native Font Def)} +%%%%%%%%%%%%% + +`xelatex -no-pdf example' + +\Link[http://en.wikipedia.org/wiki/XeTeX]{}{}XeTeX\EndLink + + + The xetex code is at + \Link[http://scripts.sil.org/svn-public/xetex/TRUNK/]{}{}http://scripts.sil.org/svn-public/xetex/TRUNK/\EndLink{} + and xdvipdfmx is found under the texk directory. + + +%%%%%%%%%%%%% +\SubSection{Font Definition} +%%%%%%%%%%%%% + + + + + +\<scan xdv font entry\><<< + unsigned short flags; +new_font.num = (INTEGER) get_unt(4); +new_font.scale = (INTEGER) get_unt(4); +new_font.design_sz = new_font.scale; +flags = (INTEGER) get_unt(2); +`<get xdv font name`> +new_font.layout_dir = (flags & `<xdv flag vertical`>) ? 1 : 0; +new_font.rgba_color = (flags & `<xdv flag colored`>)? + (unsigned long) get_unt(4) + : + 0xffffffff; +if( flags & `<xdv flag variations`> ){ + int n = (INTEGER) get_unt(2); `%number of variations`% + int i; + for (i = 0; i < n; ++i) { `%ignore axis`% + (void) get_unt(4); + } + for (i = 0; i < n; ++i) { `%ignore value of variation`% + (void) get_int(4); +} } +(IGNORED) printf("(--- xdv font = %s (not implemented) ---)\n", new_font_name); +`<get xdv font info`> +>>> + + + +\<get xdv font name\><<< +{ int n, family_name_n, style_name_n; + U_CHAR *ch; +`% char* family_name; + char* style_name;`% + font_name_n = (INTEGER) get_unt(1); + family_name_n = (INTEGER) get_unt(1); + style_name_n = (INTEGER) get_unt(1); + n = font_name_n + 1; + ch = new_font_name = m_alloc(char, n); + while( --n ){ *ch = (int) get_unt(1); ch++; } + *ch = '\0'; + n = family_name_n + 1; +`% ch = family_name = m_alloc(char, n);`% + while( --n ){ `%*ch = (int)`% (void) get_unt(1); ch++; } + *ch = '\0'; + n = style_name_n + 1; +`% ch = style_name = m_alloc(char, n);`% + while( --n ){ `%*ch = (int)`% (void) get_unt(1); ch++; } + *ch = '\0'; +} +>>> + +REMOVE allocated mem at end of usage!! + + + + +\<entries for xetex\><<< +INTEGER layout_dir; +unsigned long rgba_color; +>>> + +% char *fam_name, *sty_name; +% INTEGER used; new_font.used = 0; + + + +\<xdv flag vertical\><<< +0x0100 +>>> + +\<xdv flag colored\><<< +0x0200 +>>> + +\<xdv flag variations\><<< +0x0800 +>>> + + + + +%%%%%%%%%%%%% +\SubSection{Within IVD} +%%%%%%%%%%%%% + + +\<font defs for xdv's idv?\><<< +(version_id == `<version xdv`>) +&& +( + (ch == `<xdv-pic-file op`>) + || + (ch == `<xdv-native-font-def op`>) + || + (ch == `<xdv-glyph-array op`>) + || + (ch == `<xdv-glyph-string op`>) +) +>>> + +\<xdv flag fonttype icu\><<< +0x0002 +>>> + +\<xdv flag fonttype atsui\><<< +0x0001 +>>> + +\<xdv font def for idv\><<< +switch( ch ){ + case `<xdv-native-font-def op`>: + `<xdv/ivd native font def`> + break; + case `<xdv-glyph-string op`>: + `<xdv/idv glyph string`> + break; + default: + printf(" ===> ---------- xdv's idv ------------ <==== %d\n" , ch); +} +>>> + +\<xdv/idv glyph string\><<< +{ + int i, glyphCount; + (void) get_unt(4); + glyphCount = (INTEGER) get_unt(2); + for( i = 0; i < glyphCount; ++i ){ + (void) get_int(4); + } + for (i = 0; i < glyphCount; ++i){ + (void) get_unt(2); + } +} +>>> + + +\<xdv/ivd native font def\><<< +{ int i, flags; + +(void) get_unt(4); `%tex_id`% +(void) get_unt(4); `%scale`% + + flags = (INTEGER) get_unt(2); + + + +if ((flags & `<xdv flag fonttype icu`>) || (flags & `<xdv flag fonttype atsui`>)) { + +for ( +i = + (INTEGER) get_unt(1) `% font name `% ++ (INTEGER) get_unt(1) `% family name `% + + (INTEGER) get_unt(1) `% style name `% +; +i>0; +i-- +){ (void) get_unt(1); } + + + + + + if( flags & `<xdv flag colored`> ){ + (void) get_unt(4); + } + +if( flags & `<xdv flag variations`> ){ + int n = (INTEGER) get_unt(2); `%number of variations`% + for (i = 0; i < n; ++i) { `%ignore axis`% + (void) get_unt(4); + } + for (i = 0; i < n; ++i) { `%ignore value of variation`% + (void) get_int(4); +} } + +} + +} +>>> + + + + +%%%%%%%%%%%%% +\SubSection{????????????????} +%%%%%%%%%%%%% + + + + + + +\<get xdv font info\><<< +`<first definition of font?`> +`<open xdv font file`> +new_font_name[font_name_n] = '\0'; +new_font.name = m_alloc(char, font_name_n + 1); +(IGNORED) strcpy((char *) new_font.name, (char *) new_font_name ); +`<family and size of font`> +`<compute mag of xdv font`> +>>> + + +\<compute mag of xdv font\><<< +new_font.mag = new_font.scale / (new_font.design_sz / 100); +>>> + + + + + + + +\<open xdv font file\><<< +{ `% FILE *font_file; + U_CHAR file_name[256]; `% + `<search dirs for xdv font`> +/* + if( font_file == NULL ){ + dump_env(); err_i_str(1,file_name); + missing_fonts = TRUE; + new_font.char_f = 2; + new_font.char_l = 1; + } else { +*/ + `<get xdv chars dimensions`> +/* + (IGNORED) fclose(font_file); + } +*/ +} +>>> + + +\<get xdv chars dimensions\><<< +{ `<vars for reading xdv font file`> + `<scan xdv dimension of components of font file`> + `<scan XDV header of font file`> + `<scan xdv char info words`> + `<scan xdv width table`> + `<scan xdv height table`> + `<scan XDV depth table`> + `<scan XDV italic correction table`> + `<scan XDV lig/kern table`> + `<scan XDV kern table`> + `<scan XDV extensible character table`> + `</xdv fontdimen parameters`> +} +>>> + + + + + + +\</xdv fontdimen parameters\><<< +`<xdv font slant`> `%all need design_size_to_pt(n)`% +`<xdv interword space`> +`<XDV interword stretch`> +`<XDV interword shrink`> +`<xdv ex height`> +`<XDV em width (=quad width)`> +`<XDV extra space`> +>>> + + +\<xdv font slant\><<< +new_font.it = 0; +>>> + + +\<xdv interword space\><<< +new_font.word_sp = 350000; +`<adjust inter-word space`> +>>> + +\<ex height\><<< +new_font.ex = 450000; +>>> + + +\<scan xdv dimension of components of font file\><<< +new_font.char_f = 0; +new_font.char_l = 255; +new_font.wtbl_n = 0; +new_font.htbl_n = 0; +new_font.dtbl_n = 0; +>>> + + +it_correction_table_length = 0; +lig_kern_table_length = 0; +kern_table_length = 0; +extensible_char_table_length = 0; +num_font_parameters = 0; + +\<vars for reading xdv font file \><<< + int + it_correction_table_length, + lig_kern_table_length, + kern_table_length, + extensible_char_table_length, `%<= 256`% + num_font_parameters; +>>> + + +\<scan xdv char info words\><<< +{ U_CHAR *ch, *hidp; + int i; + ch = new_font.char_wi = m_alloc(char, new_font.char_l + - new_font.char_f + 1); + hidp = new_font.char_hidp = m_alloc(char, new_font.char_l + - new_font.char_f + 1); + for( i = new_font.char_f; i <= new_font.char_l; i++ ){ + *(ch++) = 10; + *(hidp++) = 26; +} } +>>> + + +\<scan xdv width table\><<< +{ INTEGER *p; `%needs design_size_to_pt(n)`% + int i; + p = new_font.wtbl = m_alloc( INTEGER, new_font.wtbl_n); + for( i = 0; i < new_font.wtbl_n; i++ ){ + *(p++) = 600000; +} } +>>> + + + +\<scan xdv height table\><<< +{ INTEGER *p; `%needs design_size_to_pt(n)`% + int i; + p = new_font.htbl = m_alloc( INTEGER, new_font.htbl_n); + for( i = 0; i < new_font.htbl_n; i++ ){ + *(p++) = 600000; +} } +>>> + + + + + + +\<skip font xdv def\><<< + unsigned short flags; +for( i=0; i<8; i++ ){ ch = get_char(); } +flags = (INTEGER) get_unt(2); +for( i = (INTEGER) get_unt(1) `% font name `% + + (INTEGER) get_unt(1) `% font family name`% + + (INTEGER) get_unt(1) `% font style name `% + ; i>0 + ; i-- ){ ch = get_char(); } +if( flags & `<xdv flag colored`> ){ (void) get_unt(4); } +if( flags & `<xdv flag variations`> ){ + int n = (INTEGER) get_unt(2); + int i; + for (i = 0; i < n; ++i) { + (void) get_unt(4); + } + for (i = 0; i < n; ++i) { + (void) get_int(4); +} } +>>> + + + +\<do glyph array\><<< +doGlyphArray(TRUE); +>>> + + +\<do glyph string\><<< +doGlyphArray(FALSE); +>>> + + + + + +\<header functions\><<< +static void doGlyphArray( ARG_I(BOOL) ); +>>> + +\<functions\><<< +`[ +static void doGlyphArray(yLocs) + BOOL yLocs +;{ int i, glyphCount; + (void) get_unt(4); + glyphCount = (INTEGER) get_unt(2); + for( i = 0; i < glyphCount; ++i ){ + (void) get_int(4); + if( yLocs ){ (void) get_int(4); } + } + for (i = 0; i < glyphCount; ++i){ + (void) get_unt(2); + } +} +>>> + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Connecting to the Font Table} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Verify that Font has not been Already Defined} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<first definition of font?\><<< +{ int i; + for( i=font_tbl_size-1; i>0; i-- ) + if( new_font.num == font_tbl[i].num ) warn_i(10); } +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Access to Fonts} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<search font in font-tbl\><<< +cur_fnt = search_font_tbl( cur_fnt ); +word_sp = `<size of space`>; +>>> + +\<header functions\><<< +static int search_font_tbl( ARG_I(int) ); +>>> + +\<functions\><<< +`[ +static int search_font_tbl( cur_fnt ) + int cur_fnt +;{ int i; + for( i=0; i<font_tbl_size; i++){ + if( font_tbl[i].num == cur_fnt ){ return i; } + } + err_i_int( 6,cur_fnt ); + return 0; +} +>>> + + + + + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Opening a Font File} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<open font file\><<< +{ FILE *font_file; + U_CHAR file_name[256]; + `<search dirs for font`> + if( font_file == NULL ){ + dump_env(); err_i_str(1,file_name); + missing_fonts = TRUE; + new_font.char_f = 2; + new_font.char_l = 1; + } else { + `<get chars dimensions`> + (IGNORED) fclose(font_file); +} } +>>> + + + +Some TeX systems provide virtual fonts without tfm files. Instead, they +provide file of aliases with records of the form `{\it virtual font +name}={\it actual font name}'. In such a case, the location of a file of +aliases can be provided within an a-record in \''tex4ht.env'. + +The tex4ht program ignores records having form different than `{\it + virtual font name}={\it actual font name}'. + +The full names should be provided, without the .tfm extensions (e.g., +gbksong33=GBKSONG33). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Scanning a Font File} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +TFM = TeX font metric + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Layout} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Dimensions are expressed in printers' point units. + +\<get chars dimensions\><<< +{ `<vars for reading font file`> + `<scan dimension of components of font file`> + `<scan header of font file`> + `<scan char info words`> + `<scan width table`> + `<scan height table`> + `<scan depth table`> + `<scan italic correction table`> + `<scan lig/kern table`> + `<scan kern table`> + `<scan extensible character table`> + `</fontdimen parameters`> +} +>>> + +% (IGNORED) fseek(G_fontfp,(long)0,FROM_START); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Breakdown} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<scan dimension of components of font file\><<< +file_length = (INTEGER) fget_int(font_file,2); +header_length = (int) fget_int(font_file,2); +new_font.char_f = (int) fget_int(font_file,2); +new_font.char_l = (int) fget_int(font_file,2); +new_font.wtbl_n = (int) fget_int(font_file,2); +new_font.htbl_n = (int) fget_int(font_file,2); +new_font.dtbl_n = (int) fget_int(font_file,2); +it_correction_table_length = (int) fget_int(font_file,2); +lig_kern_table_length = (int) fget_int(font_file,2); +kern_table_length = (int) fget_int(font_file,2); +extensible_char_table_length = (int) fget_int(font_file,2); +num_font_parameters = (int) fget_int(font_file,2); +if( file_length != ( 6 + header_length + - new_font.char_f + new_font.char_l + 1 + + new_font.wtbl_n + new_font.htbl_n + + new_font.dtbl_n + it_correction_table_length + + lig_kern_table_length + kern_table_length + + extensible_char_table_length + num_font_parameters ) + ){ err_i_str(15,file_name); } +>>> + + + + + +Shouldn't the hight table be of the same dim of the width and depth table? + +\<vars for reading font file\><<< + INTEGER file_length; `%all lengths are in words`% + int header_length, + it_correction_table_length, + lig_kern_table_length, + kern_table_length, + extensible_char_table_length, `%<= 256`% + num_font_parameters; +>>> + + +\<entries from font file into font-tbl\><<< + INTEGER design_pt; `%needs design_size_to_pt(n)`% + int char_f, char_l; `%0 --- 255`% + U_CHAR *char_wi; + U_CHAR *char_hidp; + int wtbl_n; + int htbl_n; + int dtbl_n; + INTEGER *wtbl; `%needs design_size_to_pt(n)`% + INTEGER *htbl; `%needs design_size_to_pt(n)`% + INTEGER *dtbl; `%needs design_size_to_pt(n)`% + INTEGER word_sp; `%needs design_size_to_pt(n)`% + INTEGER it; `%needs design_size_to_pt(n)`% + INTEGER ex; `%needs design_size_to_pt(n)`% +>>> + +Character codes beyond 255 assume the same width as their +counterpart modulo 256 characters. + +\Verbatim + header : array [0 -- lh - 1] of stuff +char_info: array [bc -- ec] of char_info_word + width : array [0 -- nw - 1] of fix_word + height: array [0 -- nh - 1] of fix_word + depth : array [0 -- nd - 1] of fix_word + italic: array [0 -- ni - 1] of fix_word + lig_kern: array [0 -- nl - 1] of lig_kern_command + kern: array [0 -- nk - 1] of fix_word + exten: array [0 -- ne - 1] of extensible_recipe + param : array [1 -- np] of fix_word +\EndVerbatim + +\SubSection{Header Information} + +\<scan header of font file\><<< +`<scan checksum in font file`> +`<scan design size in font file`> +(IGNORED) fseek(font_file, (long) ((header_length - 2) * 4), `<relative file addr`>); +>>> + +Incompatible fonts shouldn't agree in their check sum. A zero check +sum should be disregarded. + +\<scan checksum in font file\><<< +{ INTEGER checksum; + checksum = ( INTEGER) fget_int(font_file,4); + if( checksum && new_font_checksum + && (checksum != new_font_checksum) ) + { warn_i(16); + (IGNORED) fprintf(stderr,"%s: %d\ndvi file: %d\n",file_name, + checksum, new_font_checksum); +} } +>>> + +% if( ((checksum = ( INTEGER) fget_int(font_file,4)) != NULL ) + +The design size of a font is represented in +point units of \TeX, and it must be greater than 1.0. +The representation uses 32-bit words, with the leading 12 bits +providing the integer part and the two-complement of a word providing +negative values. The allowed values are in the range of +$2048-2^{-20}$ to $-2048$. + +\<scan design size in font file\><<< +new_font.design_pt = ( INTEGER) fget_int(font_file,4); `%needs design_size_to_pt(n)`% +>>> + +Skipped optional identification of coding scheme (40 bytes), +identification of font family (20 bytes), etc. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Character Information} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<scan char info words\><<< +{ U_CHAR *ch, *hidp; + int i; + ch = new_font.char_wi = m_alloc(char, new_font.char_l + - new_font.char_f + 1); + hidp = new_font.char_hidp = m_alloc(char, new_font.char_l + - new_font.char_f + 1); + for( i = new_font.char_f; i <= new_font.char_l; i++ ){ + *(ch++) = (int) fget_unt(font_file,1); + *(hidp++) = (int) fget_unt(font_file,1); + (IGNORED) fseek(font_file, 2L, `<relative file addr`>); +} } +>>> + + +Next comes the \`'char_info' array, in which +each word contains the following information for one character. + +\List{$\circ$} + +\item Width index: 8 bits +\item Height index: 4 bits +\item Depth index: 4 bits +\item Italic index: 6 bits +\item Tag: 2 bits +\item Other: 8 bits whose interpretation depends on the value of the tag. + +\List{} + +\item {0.} Ignore. + +\item {1.} An index into the \`'lig_kern' table. + +\item {2.} The character code of the next character in +a list of size-inreasing characters. + +\item {3.} An index, called extensible index, into the table \`'exten' +where the components of the current composite character are specified. +\EndList + +\EndList + + + The width of a character is \`'width[width index] * design_pt', etc. +This compression scheme allows characters of a font to choose from 256 +width-values, 16 height-values, etc. Since +\`'width[0]=height[0]=depth[0]=italic[0]=0', a character in the font +should never have a zero index. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Width Table} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<scan width table\><<< +{ INTEGER *p; `%needs design_size_to_pt(n)`% + int i; + p = new_font.wtbl = m_alloc( INTEGER, new_font.wtbl_n); + for( i = 0; i < new_font.wtbl_n; i++ ){ + *(p++) = ( INTEGER) fget_int(font_file,4); +} } +>>> + +The above fits with measurements made for the fixed-sized font cmtt10, but +not with the following measurements made for cmsy10. + +\Verbatim +182045, 327681, 509726, 509726, 436908, 436908, 436908, 509726, +509726, 655361, 327681, 327681, 509726, 509726, 655361, 400498, +509726, 509726, 436908, 436908, 364090, 364090, 509726, 655361, +655361, 655361, 473316, 327681, 509726, 509726, 509726, 436908, +344061, 655361, 327681, 327681, 655361, 655361, 655361, 212991, +655361, 655361, 327681, 400498, 327681, 509726, 436908, 473316, +180223, 655361, 436908, 436908, 582543, 582543, 344061, 344061, +364090, 364090, 436908, 327681, 473316, 473316, 509726, 509726, +400498, 523286, 450377, 383297, 523745, 404502, 536119, 428716, +559789, 405233, 565248, 508817, 452018, 787021, 634289, 539946, +509726, 535213, 555420, 446006, 523509, 475226, 455478, 701238, +563429, 491886, 527019, 436908, 327681, 436908, 436908, 247723, +400498, 400498, 291271, 291271, 291271, 291271, 327681, 327681, +254863, 254863, 182045, 327681, 327681, 400498, 671742, 182045, +546135, 491521, 546135, 345886, 436908, 436908, 509726, 509726, +291273, 291271, 291271, 327681, 182045, 327681, 509726, 345886 +\EndVerbatim + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Height Table} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<scan height table\><<< +{ INTEGER *p; `%needs design_size_to_pt(n)`% + int i; + p = new_font.htbl = m_alloc( INTEGER, new_font.htbl_n); + for( i = 0; i < new_font.htbl_n; i++ ){ + *(p++) = ( INTEGER) fget_int(font_file,4); +} } +>>> + +For instance, the following table for cmr10 + +\Verbatim +0, 110683, 384696, 451470, 524288, 553416, 595357, 611670, +644958, 659002, 675749, 700301, 716526, 728178, 767499, 786432 +\EndVerbatim + + + + +\SubSection{Depth Table} + + + + +\<scan height table\><<< +{ INTEGER *p; `%needs design_size_to_pt(n)`% + int i; + p = new_font.dtbl = m_alloc( INTEGER, new_font.dtbl_n); + for( i = 0; i < new_font.dtbl_n; i++ ){ + *(p++) = ( INTEGER) fget_int(font_file,4); +} } +>>> + + + +\<scan depth tableNO\><<< + `%needs design_size_to_pt(n)`% +(IGNORED) fseek(font_file, (long) (depth_table_length * 4), + `<relative file addr`>); +>>> + + +\SubSection{Italic Correction Table} + +Used for italic correction explicitly requested with \`'\/', and for +isolated character in math mode (MetaFont 315--316). + +\<scan italic correction table\><<< + `%needs design_size_to_pt(n)`% +(IGNORED) fseek(font_file, (long) (it_correction_table_length * 4), + `<relative file addr`>); +>>> + +\SubSection{Ligature Table} + +Substitutions for specified runs of chrarcters + +\<scan lig/kern table\><<< +(IGNORED) fseek(font_file, (long) (lig_kern_table_length * 4), + `<relative file addr`>); +>>> + +\SubSection{kern table} + +Space to add between specified pairs of characters. + +\<scan kern table\><<< + `%needs design_size_to_pt(n)`% +(IGNORED) fseek(font_file, (long) (kern_table_length * 4), + `<relative file addr`>); +>>> + + + +\SubSection{Extensible Table} + +\<scan extensible character table\><<< +(IGNORED) fseek(font_file, (long) (extensible_char_table_length * 4), + `<relative file addr`>); +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Font Dimension Parameters} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +At least seven parameters used in \''\fontdimen', each occupying four +bytes (= one word). With the exception of the first parameter, all +the other parameters should be magnified for a font that is magnified +with \`'at' or \`'scaled'. + +\</fontdimen parameters\><<< +`<font slant`> `%all need design_size_to_pt(n)`% +`<interword space`> +`<interword stretch`> +`<interword shrink`> +`<ex height`> +`<em width (=quad width)`> +`<extra space`> +>>> + +\List{$\circ$} + +\item The slant per point of a font, used for determining the height + of accent characters. + +\<font slant\><<< +new_font.it = ( INTEGER) fget_int(font_file,4); +>>> + +\item In math mode the inner word space is zero and italic correction values are used. + +\<interword space\><<< +new_font.word_sp = ( INTEGER) fget_int(font_file,4); +`<adjust inter-word space`> +>>> + +The following variable needs initialization that is used before +the loading of any font. Without it, the program will enter an infinite +loop. + + +\<defines\><<< +#ifdef LONG +#define MARGINSP 344061L `%tt at 10pt`% +#else +#define MARGINSP 344061 +#endif +>>> + +\<vars\><<< +static double word_sp = 999999.0, margin_sp; +>>> + +Turbo C didn't let me to do casting within initialization. + +\<main's init\><<< +margin_sp = (double) MARGINSP; `%/ (double)(1L<<20) * (double) 655360;`% +>>> + +\<adjust inter-word space\><<< +if( new_font.word_sp == 0 ) { + int i; + for( i = new_font.char_f; i <= new_font.char_l; i++ ){ + new_font.word_sp = + ( new_font.word_sp + + + *(new_font.wtbl + (int)(*(new_font.char_wi + i - new_font.char_f))) + ) / (new_font.char_f<i? 2:1); + } } +if( new_font.word_sp == 0 ) new_font.word_sp = MARGINSP; `%fix`% +>>> + +We took for space size an approximated character width. + + +\<interword stretch\><<< +(IGNORED) fseek(font_file, 4L, `<relative file addr`>); +>>> + +\<interword shrink\><<< +(IGNORED) fseek(font_file, 4L, `<relative file addr`>); +>>> + +\item The design height of letters. + +\<ex height\><<< +new_font.ex = (INTEGER) fget_int(font_file,4); +>>> + +\item The size of one em in the font. + +\<em width (=quad width)\><<< + +>>> + +\item Extra interword space at the end of sentences. + +\<extra space\><<< + +>>> +\EndList + + +\Section{Computing Font Info} + +\SubSection{Characters' Width} + +\<return char width\><<< +return (INTEGER)( + `<(double) char_width( ch )`> + ); +>>> + + +\<(double) char_width( chr )\><<< +design_size_to_pt( *(font_tbl[cur_fnt].wtbl + + (int) `<chr width of`>) ) +* (double) font_tbl[cur_fnt].scale +>>> + + +\<chr width of\><<< +*(font_tbl[cur_fnt].char_wi + + (chr - font_tbl[cur_fnt].char_f)% 256) +>>> + + + +\<(double) char_width( design_ch? design_ch : ch )\><<< +design_size_to_pt( *(font_tbl[cur_fnt].wtbl + + (int) (`<design-ch / ch width of`>)) ) + * (double) font_tbl[cur_fnt].scale +>>> + + +\<design-ch / ch width of\><<< +*(font_tbl[cur_fnt].char_wi + (int) + ( (design_ch? design_ch : ch) - font_tbl[cur_fnt].char_f)% 256) +>>> + + + + + +\<(double) char_width( ch )\><<< +design_size_to_pt( *(font_tbl[cur_fnt].wtbl + + (int) (`<ch of width`>) ) + ) +* (double) font_tbl[cur_fnt].scale +>>> + + +\<ch of width\><<< +*(font_tbl[cur_fnt].char_wi + (int) + ( ch - font_tbl[cur_fnt].char_f)% 256) +>>> + + +\<ch width\><<< +(int)(`<(double) char_width( ch )`>) +>>> + +\SubSection{Characters' Height} + + + + +\<(double) char_height( ch )\><<< +design_size_to_pt( *(font_tbl[cur_fnt].htbl + + (int) (`<ch of height`>)) ) + * (double) font_tbl[cur_fnt].scale +>>> + + +\<ch of height\><<< +( *(font_tbl[cur_fnt].char_hidp + (int) + ( ch - font_tbl[cur_fnt].char_f)% 256) + >> 4 +) & 0x0F +>>> + + +\<ch height\><<< +(int)(`<(double) char_height( ch )`>) +>>> + +\SubSection{Characters' Depth} + + + + +\<(double) char_depth( ch )\><<< +design_size_to_pt( *(font_tbl[cur_fnt].dtbl + + (int) (`<ch of depth`>)) ) +* (double) font_tbl[cur_fnt].scale +>>> + + +\<ch of depth\><<< +( *(font_tbl[cur_fnt].char_hidp + (int) + ( ch - font_tbl[cur_fnt].char_f)% 256) +) & 0x0F +>>> + + +\<ch depth\><<< +(int)(`<(double) char_depth( ch )`>) +>>> + +\SubSection{Other Sizes} + + +\<size of ex\><<< +design_size_to_pt( 1.7 * (double) font_tbl[cur_fnt].ex ) +* (double) font_tbl[cur_fnt].scale +>>> + + +\<size of space\><<< +design_size_to_pt( font_tbl[cur_fnt].word_sp ) + * (double) font_tbl[cur_fnt].scale +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Chapter{Font Information from Htf Tables} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +The htf fonts are used only within the text part of the html files. + +Each char code $i$ in a font may be assigned a string representation +and a gif option. When the gif option is provided, the character is +taken to be a picture with ALT getting the string for nongraphical +reviewers. + +For character code i, $0\leq i\leq 255$, we maintain +\List{$\circ$} + +\item A bit in \`'*gif' to determine if this option exists: \''*gif[] >> +i & 1' + +\item A bit in \`'*gif_on' to determine if this option is used: +\''*gif_on[] >> i & 1' + +\item A bit in \`'*ch_str' to determine if the string has length different +than one. + +\item A character \`'*ch' that holds the character when the string +is of length one, +and holds an index to \`'*str' when the string is longer than 1. + +\item A pointer \`'**str[*ch[i]]' to a string, if the character has a +string of length that differs from 1. +\EndList + + +In the `.htf' files, uses line entries of the form \`'string1string2...', +where the strings have the same arbitrary open and close +delimiters. An empty second string indicate no-option gif. + + +\<entries for html chars in font-tbl\><<< +char *name, *gif_on, *ch_str, ch255; `%2000`% +unsigned U_CHAR **str, *ch, *gif1; +>>> + +The following provides a value for characters of missing fonts out of +the range 32--127. Within that range, the character codes are being +used. + +\<get ignored chars\><<< +char *digit = p+2; +ignore_ch = 0; +while( *digit != '\0' ){ + if( (*digit < '0') || (*digit > '9') ){ + ignore_ch = 0; break; + } + ignore_ch = 10 * ignore_ch + (*digit - '0'); + if( ignore_ch > 255 ){ ignore_ch = 0; break; } + digit++; +} +>>> + +\<vars\><<< +static int ignore_ch = 0; +>>> + + + + + +%%%%%%%%%%%%%%%%%%%%%%% +\Section{Load Characters} +%%%%%%%%%%%%%%%%%%%%%%% + + +In case of shared htf fonts, we can have much more sharing below. + +Lynx introduces a space before and after each figure. + + +\<get html characters\><<< +{ U_CHAR str[256]; + int i, design_n, n_gif; + `<font looping variables`> + n_gif = new_font.char_l - new_font.char_f + 1; + new_font.ch255 = 0; + `<initiate gif flags`> + `<initiate htf accents`> + new_font.ch = m_alloc(unsigned char, n_gif ); + `<set default characters`> + new_font.str = m_alloc(unsigned char*, n_gif); + new_font.str[0] = &null_str; + design_n = 0; + `<load file of characters`> + new_font.str = (unsigned U_CHAR **) r_alloc((void *) new_font.str, + (size_t) ( (design_n?design_n:1) * sizeof(char *)) ); + `<merge new html font with old ones`> +} +>>> + +A value 0 corresponds to an empty string. A value greater than 0 points to +a character string. +\`' design_n = 0;' had value 1 earlier. Probably because we had \`'design_n', +and not \`'(design_n?design_n:1)', which asked for allocation of memory of size 0. This caused a problem to mallocate, because it produced a non-valid 0 ( \`'insuffient +memory') error + +\<vars\><<< +static unsigned U_CHAR null_str = '\0'; `% /*NEW*/ `% +>>> + +\<initiate gif flags\><<< +{ int n_gif_bytes; + n_gif_bytes = (n_gif + 7) / 8; + new_font.gif_on = m_alloc(char, n_gif_bytes ); + new_font.ch_str = m_alloc(char, n_gif_bytes ); + `<memory for math classes`> + for( i=n_gif_bytes; i--; ) { + `<init math-closing`> new_font.ch_str[i] = new_font.gif_on[i] = 0; + } + new_font.gif1 = m_alloc(unsigned char, n_gif ); + for( i=n_gif; i--; ) { + `<init math`> new_font.gif1[i] = 0; +} } +>>> + +\<set default characters\><<< +for( i = new_font.char_f; i <= new_font.char_l ; i++ ){ + new_font.ch[i - new_font.char_f] = + (char) (((31<i) && (i<128))? i : ignore_ch); +} +>>> + + + + +The first iteration searches for the font directly. The second +iteration searches for aliased font. + + +\<load file of characters\><<< +{ char search_font_name [256]; + (IGNORED) strcpy((char *) search_font_name, (char *) new_font.name); + while( 1 ){ BOOL flag; + `<font looping test`> + flag = TRUE; + for( ; font_name_n; font_name_n-- ){ FILE* file; + int char_f, char_l; + new_font_name[font_name_n] = '\0'; + `<file = .htf file`> + if( file != NULL){ + INTEGER x_char_l; + `<scan header line in html font file`> + if( x_char_l == HTF_ALIAS) { + `<scan aliased htf file`> + (IGNORED) fclose(file); flag = FALSE; break; + } + `<scan info of html font file`> + `<scan trailer line in html font file`> + htf_to_lg(html_font, new_font_name, fonts_n, file); + `<trace htf files`> + (IGNORED) fclose(file); break; + } } + if( flag ){ break; } + } + if( font_name_n == 0 ){ + if( errCode == 0 ){ errCode= 21; } + warn_i_str(21,search_font_name); + (IGNORED) fprintf(stderr, + "%d--%d)\n", new_font.char_f, new_font.char_l); + dump_env(); + } else { `<trace env file`> } +} +>>> + + +\<font looping variables\><<< +int loopBound = 0; +U_CHAR loopName[256]; +loopName[0] = '\0'; +>>> + +\<font looping test\><<< +if( eq_str( new_font_name, loopName) ){ + U_CHAR name[256]; + (IGNORED) sprintf(name, "%s.htf", new_font_name); + err_i_str(1, name); +} else { + (IGNORED) strcpy((char *) loopName, (char *) new_font_name); +} +loopBound++; +if( loopBound > 10 ){ + U_CHAR name[256]; + (IGNORED) sprintf(name, "%s.htf", new_font_name); + err_i_str(1, name); +} +>>> + + +%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Aliases} +%%%%%%%%%%%%%%%%%%%%%%% + +\<if alias return 0\><<< +if( ( name == new_font_name ) && (n == 19) && (ch=='.') ){ + return HTF_ALIAS; +} +>>> + + + +\<defines\><<< +#define HTF_ALIAS 10000000 +>>> + + + + + + + +\ifHtml[\HPage{more} +Was \`' printf("%d--%d)\n", new_font.char_f, new_font.char_l);' + +\Verbatim + Something I noticed while working on the redirection program: + + - When a warning message is given about a missing .htf file, the first +part: + + --- warning --- Couldn't find `.htf' file for font `cmitt10' (char codes: + +is printed to stderr, while the second part: + + 0--127) + +is printed to stdout. This looks silly if you redirect stdout but not +stderr, as you'll see only the second halve in the log file. (I do +intend to expand my redirection utility to include stderr, if desired, +but I think this should be fixed anyway). +\EndVerbatim +\EndHPage{}]\fi + + + + + + + + + + + +\<scan aliased htf file\><<< +{ int chr; + font_name_n=0; + while( (chr = get_html_ch(file)) != '\n' ){ + if( chr != ' ' ) search_font_name[font_name_n++] = chr; + } + search_font_name[font_name_n] = '\0'; + if( eq_str( search_font_name, new_font_name) ){ err_i_str(20, new_font_name); } + (IGNORED) printf("Searching ``%s.htf' for ``%s.htf'\n", + search_font_name, new_font.name); + htf_to_lg(html_font, new_font_name, fonts_n, file); + new_font_name = (char *) r_alloc((void *) new_font_name, + (size_t) (font_name_n+1)); + (IGNORED) strcpy((char *) new_font_name, (char *) search_font_name); + font_name_n = strlen((char *) new_font_name); +} +>>> + + + + + + + + +\<get replacement fontNO\><<< +if( dot_file ){ BOOL tag; + (IGNORED) fseek(dot_file, 0L, `<abs file addr`>); + tag = TRUE; + while( tag ){ + switch( getc(dot_file) ){ + case EOF: { j++; tag = FALSE; break; } `%no replacement`% + case 'a': { `<scan replacement font`> } + default: { int ch; + do ch = getc(dot_file); + while( (ch != '\n') && (ch != EOF) ); + break; } +} } } +>>> + + +\<scan replacement fontNO\><<< + int chr; + U_CHAR *ch; +ch = new_font.name; +while( *ch++ == (chr = getc(dot_file)) ); +if( chr==' ' ){ + tag = FALSE; + while( (new_font_name[0] = getc(dot_file)) == ' ' ); + font_name_n=1; + while( (chr = getc(dot_file)) != '\n' ) + if( chr != ' ' ) new_font_name[font_name_n++] = chr; + new_font_name[font_name_n] = '\0'; + (IGNORED) printf("Loading ``%s.htf' for ``%s.htf'\n", + new_font_name, new_font.name); +} +>>> + + + + +\Section{Merge Tables} + +Don't we loose some vital info here? Were this comes from? + +\<merge new html font with old ones\><<< +for( i = fonts_n; i--; ) + if( eq_str(html_font[i].name, new_font_name) ){ int k; + k = html_font[i].i; + free((void *) new_font.gif1 ); new_font.gif1= font_tbl[ k ].gif1; + free((void *) new_font.ch ); new_font.ch = font_tbl[ k ].ch; + free((void *) new_font.str ); new_font.str = font_tbl[ k ].str; + free((void *) new_font.ch_str ); + new_font.ch_str = font_tbl[ k ].ch_str; + `<merge math entries`> + break; } +if( i < 0 ){ `<record new tex4ht font`> } +>>> + + +\<record new tex4ht font\><<< +html_font = fonts_n? (struct html_font_rec *) r_alloc((void *) html_font, + (size_t) ((fonts_n+1) * sizeof(struct html_font_rec) )) + : m_alloc(struct html_font_rec, 1); +html_font[fonts_n].name = m_alloc(char, font_name_n + 1); +(IGNORED) strcpy((char *) html_font[fonts_n].name, (char *) new_font_name); +html_font[fonts_n].i = font_tbl_size; +fonts_n++; +>>> + +\<scan fonts vars\><<< +int fonts_n; +struct html_font_rec *html_font=0; +>>> + +\<init scan fonts vars\><<< +fonts_n = 0; +>>> + +\<free html font memory\><<< +if( html_font ){ + while( fonts_n-- ) free((void *) html_font[fonts_n].name); + free((void *) html_font ); +} +>>> + +EXPLAIN THE CONTENT OF THE FOLLOWING + +\<types\><<< +struct html_font_rec{ char* name; + int i; }; +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Scan Characters} +%%%%%%%%%%%%%%%%%%%%%%%%% + +\<scan info of html font file\><<< +if( char_f <= new_font.char_l ){ U_CHAR del; + int j, n; + `<skip front part in font file`> + n = ((char_l < new_font.char_l)? char_l : new_font.char_l) + - char_f + 1; + for( i = char_f - new_font.char_f; i < n; i++ ){ + `<scan html char in font file`> + `<store html character`> } + `<skip back part of font file`> +} +>>> + + +\<skip front part in font file\><<< +while( char_f < new_font.char_f ){ + while( get_html_ch(file) != '\n' ); + char_f++; } +>>> + +\<skip back part of font file\><<< +while( char_l > new_font.char_l ){ + while( get_html_ch(file) != '\n' ); + char_l--; } +>>> + +We should consider characters having representations of \`'\decimal +digits\', \`'\x hexadecimal digits\', and \`'\o octal digits\'. + +\<scan html char in font file\><<< +{ int indirect_ch, base=0, value=0, digit, ch1`%, ch2`%; + indirect_ch = 0; + del = get_html_ch(file); j=0; + while( (str[j++] = get_html_ch(file)) != del ) + { `<check for encoded chars`> }; + str[j-1] = '\0'; + while( get_html_ch(file) != del ); + ch1 = 0; + while( ((ch = (int) get_html_ch(file)) != del) ){ + if( (ch < '0') || (ch > '9') ) break; + ch1 = ch1 * 10 + ch - '0'; } + `<propagate 4hf info into htf`> + new_font.gif1[i] = ch1 % 256; + do{ + if( (ch = get_html_ch(file)) == del ){ + `<scan htf accent`> break; + } + } while( ch != '\n' ); + if( ch != '\n' ){ + do{ + if( (ch = get_html_ch(file)) == del ){ + `<scan htf accented`> break; + } + } while( ch != '\n' ); + } + if( ch != '\n' ) + { while( get_html_ch(file) != '\n' ); } +} +>>> + + + + +\<check for encoded chars\><<< +if( (digit=str[j-1]) == '\\' ) + if( (indirect_ch = !indirect_ch) != 0) { + switch( value=get_html_ch(file) ){ + case 'x': { base = 16; value = 0; j--; break; } + case 'o': { base = 8; value = 0; j--; break; } + default: { + if( (value < '0') || (value > '9') ) { + indirect_ch = !indirect_ch; str[j-1] = value; + } else { value -= '0'; base = 10; j--; } + } } } + else{ if( value>255 ){ + warn_i_int(28,value); + value = 32; dump_htf( file ); + } + str[j-1] = value; + } +else if ( indirect_ch ){ + j--; digit -= (digit>'9')? 'A'-10 : '0'; + if( (digit<0) || (digit>=base) ){ + warn_i_int(29, str[j]); + digit = 0; dump_htf( file ); + } + value = value*base + digit; +} else if ( str[j-1]==10 ){ + dump_htf( file ); + err_i_int(48, i+1); +} +>>> + + +We might be able in the following to share strings by comparing with +corresponding characters in other fonts. + + + + +The variable j holds the number of characters in the string plus +one. + + + + +\<store html character\><<< +add_bit( new_font.ch_str, i, j!=2 ); +switch( j ){ + case 1: { new_font.ch[i] = 0; break; } + case 2: { new_font.ch[i] = *str; break; } + default: { unsigned U_CHAR *p; + new_font.str[design_n] = p = m_alloc(unsigned char, j); + if( design_n>255 ){ design_n--; warn_i(35);} + if( i==255 ){ + if( design_n == 255 ){ + new_font.ch[i] = 0; new_font.ch255 = 1; + } else { new_font.ch[i] = ++design_n; } + } else { new_font.ch[i] = ++design_n; } + while( j-- ) p[j] = str[j]; `%2000`% +} } +>>> + + + + + + + + + + +\<header functions\><<< +static int get_html_ch( ARG_I(FILE*) ); +>>> + +\<functions\><<< +`[ +static int get_html_ch( file ) FILE* file + +;{ int ch; + if( (ch = (int) getc(file)) == EOF ) { + dump_htf( file ); + err_i_str(20, new_font_name); + } + return ch; +} +>>> + + + + + +\<header functions\><<< +static FILE* f_open( ARG_II(const char*,const char*) ); +>>> + +\<functions\><<< +`[ +static FILE* f_open( name, flags ) + const char* name `; + const char* flags +;{ FILE* file; + if( (file = fopen(name,flags) ) != NULL ) { + (IGNORED) printf("(%s)\n",name); + } + return file; +} +>>> + + + + + + + + +\<header functions\><<< +static void dump_htf( ARG_I(FILE*) ); +>>> + +\<functions\><<< +`[ +static void dump_htf( file ) FILE* file + +;{ int i, j, ch, chr=0; + (IGNORED) fseek(file, 0L, 0); + i=-1; j=0; + while( (ch = getc(file)) != EOF ){ + if( !j ){ chr = ch; } + j += ch==chr; + (IGNORED) putc(ch,stderr); + if( ch == '\n' ){ + if( (i>-1 ) && (j<4) && (dump_htf_files<2) ){ + (IGNORED) printf("missing delimiter \n"); + } + (IGNORED) fprintf(stderr,"%d: ",++i); + j=0; +} } } +>>> + + + +\<vars\><<< +static short dump_htf_files = 0; +static BOOL dump_env_files = FALSE; +>>> + +\<dump htf files\><<< +dump_htf_files = 1; +>>> + +\<dump env file\><<< +dump_env_files = TRUE; +>>> + +\<trace htf files\><<< +if( dump_htf_files ){ + dump_htf_files++; dump_htf( file ); dump_htf_files--; +} +>>> + +\<trace env file\><<< +if( dump_env_files ){ dump_env(); } +>>> + + + + +\<header functions\><<< +static void dump_env( ARG_I(void) ); +>>> + +\<functions\><<< +static void dump_env( MYVOID ) +{ + int ch; + if( !dumped_env ){ + dumped_env = TRUE; + (IGNORED) fseek(dot_file, 0L, `<abs file addr`>); + (IGNORED) fprintf(stderr, + "\n----------------------------------------------------\n"); + (IGNORED) fprintf(stderr, "environment file\n"); + (IGNORED) fprintf(stderr, + "----------------------------------------------------\n"); + while( (ch = getc(dot_file)) != EOF ){ + (IGNORED) putc(ch,stderr); + } + (IGNORED) fprintf(stderr, + "----------------------------------------------------\n"); +} } +>>> + +\<vars\><<< +static BOOL dumped_env = FALSE; +>>> + + + + + + +\<header functions\><<< +static void htf_to_lg( ARG_IV(struct html_font_rec*,char*,int,FILE*)); +>>> + +\<functions\><<< +`[ +static void htf_to_lg(html_font, new_font_name, fonts_n, file) + + struct html_font_rec* html_font`; + char* new_font_name`; + int fonts_n`; + FILE* file +;{ + int ch, i; + for( i = 0 ; i<fonts_n; ){ + if( eq_str(html_font[i].name, new_font_name) ){ break; } + i++; + } + if( i == fonts_n ){ + BOOL content; + int prev_ch; + prev_ch = '\n'; content = FALSE; + while( (ch = (int) getc(file)) != EOF ) { + if( (ch != '\n') || (prev_ch != '\n') ){ + (void) putc( ch, log_file ); + prev_ch = ch; content = TRUE; + } } + if( content && (prev_ch != '\n') ){ + (void) putc( '\n', log_file ); + } +} } +>>> + + + +\<scan header line in html font file\><<< +x_char_l = + get_html_file_id(file, new_font.char_f, new_font.char_l, 19); +if( x_char_l != HTF_ALIAS) { + char_f = (int) (x_char_l / 1000.0 + 0.5) + new_font.char_f; + x_char_l -= (char_f-new_font.char_f) * 1000 - new_font.char_l; + char_l = (int) x_char_l; +} +>>> + + +\<scan trailer line in html font file\><<< +(void) get_html_file_id(file, new_font.char_f, new_font.char_l, 18); +>>> + +\<header functions\><<< +static INTEGER get_html_file_id( ARG_IV(FILE*, int, int, int) ); +>>> + +\<functions\><<< +`[ +static INTEGER get_html_file_id(file, first, last, n) + FILE* file`; + int first`; int last`; int n + +;{ int ch, i, bound, cnt; + INTEGER diff; + char* name; + name = new_font_name; + while( *name == (ch = get_html_ch(file)) ) name++; + `<if alias return 0`> + if( (*name != '\0') || (ch != ' ') ) warn_i_str(n, name); + bound = first; diff = 0; + for( cnt = 0; cnt < 2; cnt++ ){ + while( ch == ' ' ) ch = get_html_ch(file); + i = 0; + while( (ch >= '0') && (ch <= '9') ){ + i = i * 10 + ch - '0'; ch = get_html_ch(file); } + if( i != bound ){ + `<warning(22`>, new_font_name, i, bound); show_err_context(); + diff = diff * 1000 + i - bound; } + bound = last; } + while( ch != '\n' ) ch = get_html_ch(file); + return diff; +} +>>> + +\<defines\><<< +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef BOOL +#define BOOL int +#endif +>>> + + + + +\Section{Use of Characters} + + +When \''next_char' is not equal to -1, there is a character waiting to +replace the current character. + + +\<insert ch to text\><<< +`<set begin accents`> +`<css for chars`> `<trace dvi char`> +`<left class del`> `<pos dvi ch`> +`<mark accented ch`> +if( `<next-char`> != -1 ) { + `<open output file`> + (IGNORED) put_4ht_ch( `<next-char`>, cur_o_file ); + `<next-char`> = -1; +} else if( `<next-str`> ) { + `<current char for forwarded string`> + print_f_4ht(next_str); free((void *) next_str); + next_str = (char *) 0; +} else { + if( verb_ch ){ + `<open output file`> + (IGNORED) put_4ht_ch( ch, cur_o_file ); + } else { `<insert font char`> } +} +`<end mark accented ch`> +`<end pos dvi ch`> `<right class del`> +`<end trace dvi char`> `<end css for chars`> +`<set end accents`> +>>> + + +Does \`'verb_ch' correspond to \''\Char'? + + +\<insert font char\><<< + int gif_flag, chr, r_ch; + BOOL ch_str_flag; +r_ch = ch - font_tbl[cur_fnt].char_f; +gif_flag = font_tbl[cur_fnt].gif1[r_ch]; +ch_str_flag = get_bit( font_tbl[cur_fnt].ch_str, r_ch); +chr = ((r_ch == 255) && font_tbl[cur_fnt].ch255 )? 256 : + *(font_tbl[cur_fnt].ch + r_ch); +if( (gif_flag % 2) || ch_str_flag ){ design_ch = ch; + { `<insert design chr`> } design_ch = 0; } +else { `<insert standard char`> } +>>> + + + +\<vars\><<< +static BOOL verb_ch = FALSE; +>>> + + +A design character is either a picture (\''gif_flag') or +a string character (\''ch_str_flag'). + +\<insert design chr\><<< + U_CHAR str[256], *p; + BOOL sv; + int mag; +sv = special_on; special_on = TRUE; +if( gif_ch && (gif_flag % 2) ){ + `<open output file`> + if( !gif_open[gif_flag] ){ + `<img char without template`> + } else if( !get_bit( class_on, gif_flag ) ) { + notify_class_info(gif_flag); + store_bit_I( class_on, gif_flag ); + } + `<<IMG SRC="...`> + `<..."ALT="...`> + `<..."CLASS="family...`> + `<...gif font size...`> + `<...gif font mag...`> + `<...gif sym ord...`> + `<..."/IMG>`> +} else { `<insert string char`> } +special_on = sv; +>>> + + + + + +\<header functions\><<< +static void notify_class_info( ARG_I(int) ); +>>> + +\<functions\><<< +`[ +static void notify_class_info( gif_flag ) int gif_flag +;{ U_CHAR str[256], *p; + str[0] = '\0'; + p = gif_open[gif_flag]; + if( p ) + if( *p ) (IGNORED) strct(str,p); + p = gif_alt[gif_flag]; + if( p ) + if( *p ) (IGNORED) strct(str,p); + p = gif_class[gif_flag]; + if( p ) + if( *p ) (IGNORED) strct(str,p); + p = gif_size[gif_flag]; + if( p ) + if( *p ) (IGNORED) strct(str,p); + p = gif_mag[gif_flag]; + if( p ) + if( *p ) (IGNORED) strct(str,p); + p = gif_ord[gif_flag]; + if( p ) + if( *p ) (IGNORED) strct(str,p); + p = gif_end[gif_flag]; + if( p ) + if( *p ) (IGNORED) strct(str,p); + p = str; + while( *p ){ + if( *p == '\n' ) *p = ' '; + p++; + } + (IGNORED) fprintf(log_file, class_fmt, + gif_flag, + gif_id[gif_flag]? gif_id[gif_flag] : "", + str); +} +>>> + +For some reason, bordlan cc+ complains if the +\`'p = gif_open[gif_flag]' are placed within the if's. + +\`'configuration for class %d' below stands for +\`'\\special{t4ht;|%d...}' + + +\<img char without template\><<< +(IGNORED) sprintf(str, + "configuration for htf class %d (char %d of %s.htf)", + gif_flag, ch,font_tbl[cur_fnt].name + ); +warn_i_str(50,str); +>>> + +\<img char without template\><<< +gif_open[gif_flag] = m_alloc(char, + `<1 + strlen((char *) <IMG SRC="+"ALT="+++++">+)`>); +(IGNORED) strcpy((char *) gif_open[gif_flag], + `<<IMG SRC="+"ALT="+++++">+`>); +gif_alt[gif_flag] = gif_open[gif_flag]+11; + *(gif_alt[gif_flag] - 1) = '\0'; +gif_class[gif_flag] = gif_open[gif_flag]+19; + *(gif_class[gif_flag] - 1) = '\0'; +gif_size[gif_flag] = gif_open[gif_flag]+20; + *(gif_size[gif_flag] - 1) = '\0'; +gif_mag[gif_flag] = gif_open[gif_flag]+21; + *(gif_mag[gif_flag] - 1) = '\0'; +gif_ord[gif_flag] = gif_open[gif_flag]+22; + *(gif_ord[gif_flag] - 1) = '\0'; +gif_end[gif_flag] = gif_open[gif_flag]+23; + *(gif_end[gif_flag] - 1) = '\0'; +gif_id[gif_flag] = gif_open[gif_flag]+28; + *(gif_id[gif_flag] - 1) = '\0'; +>>> + +\<<IMG SRC="+"ALT="+++++">+\><<< +"<img src=\"+\" alt=\"+++++\" />+" +>>> + +\<1 + strlen((char *) <IMG SRC="+"ALT="+++++">+)\><<< +29 +>>> + +% `<..."IMG OPTIONS="...NOT`> + + +What is the difference between the following two cases? + + +\<insert standard char\><<< +if( !gif_flag || (gif_flag % 2) || ch_map_flag ) { put_char(chr); +} else{ `<put char(chr)`> } +>>> + +If \`'gif_flag % 2' is the case we have a picture which we want to +insert for it just the string part. (The !gif_flag is for text with +pattermn 0?) + +\<insert string char\><<< +if( !gif_flag || (gif_flag % 2) || ch_map_flag ) { + put_alt_ch(chr,ch_str_flag); } +else{ `<put string-char(chr)`> } +>>> + + +\SubSection{Script class-fmt} + +Font information, e.g., for style files. + +\<h-defines\><<< +#ifndef LGCLS +#define LGCLS "Font_Class(%d,\"%s\"): %s\n" +#endif +>>> + + +\<vars\><<< +static U_CHAR *class_fmt = NULL; +>>> + + + +\<get from tex4ht.env file\><<< +class_fmt = (char *) get_script(class_fmt,LGCLS,'c'); +>>> + + + + +\SubSection{File Names for Gifs} + +Symbol i from base font x gets into file \`'x-i.gif', and from +c-magnified font goes into \`'x-c-i.gif'. In old LaTeX, +\`'\documentstyle[...12p..]{..}' gives a based-10 font magnified into 12. + + + +\<defines\><<< +#define GIF_I "-%x%s" +#define GIF_II "-%x-%x%s" +#define GIF_VII "%s" +>>> + + + +\<h-defines 2\><<< +#ifdef DOS +#define HTM +#endif +>>> + +\<defines\><<< +#ifdef HTM +#define DOS_GIF_FILE +#endif +>>> + + + + + +\<insert gif symbol to html file\><<< +if( !dos_file_names ){ + print_f(font_tbl[cur_fnt].name); + if( mag == 10 ) (IGNORED) sprintf(str, GIF_I, design_ch, gif); + else (IGNORED) sprintf(str, GIF_II, mag, design_ch, gif); +} +>>> + +\<insert gif symbol to lg file\><<< +if( !dos_file_names ){ + if( mag == 10 ) (IGNORED) sprintf(str, "%s-%x%s", + font_tbl[cur_fnt].name, ch, gif); + else (IGNORED) sprintf(str, "%s-%x-%x%s", + font_tbl[cur_fnt].name, mag, ch, gif); +} +>>> + + +Transform long file names to 8 characters. + + +\<insert gif symbol to html file\><<< +`% +#ifdef DOS_GIF_FILE +`% +if( dos_file_names ){ + dos_gif_file(str, mag, design_ch); + print_f(str); + (IGNORED) sprintf(str, GIF_VII, gif); +} +`% +#endif +`% +>>> + + +\<insert gif symbol to lg file\><<< +`% +#ifdef DOS_GIF_FILE +`% +if( dos_file_names ){ + (IGNORED) strcpy((char *) str, (char *) font_tbl[cur_fnt].name); + dos_gif_file(str, mag, ch); + strct(str,gif); +} +`% +#endif +`% +>>> + + + + + +The following writes into the \`'.lg' file. The \`'templt' ends with +a percent (\''%\0'). The algorithm collects the characters +until a \''%' is encountered. Then it prints out the segment of +characters accumulated, and goes to process whatever follows the \`'%'. + + +\<header functions\><<< +static void script( ARG_IV(char *, U_CHAR *, int, U_CHAR *) ); +>>> + +\<functions\><<< +`[ +static void script(templt, job, page, font) + U_CHAR *templt`; + U_CHAR *job`; + int page`; + U_CHAR *font + +;{ U_CHAR *ch, *p; + U_CHAR fmt[256]; + job[ (int) strlen((char *) job) - 1 ] ='\0'; + p = ch = templt; + while( TRUE ){ + if( *ch == '%' ){ + `<print segment of templet`> + `<get format of output`> + switch( *(++ch) ){ + case '1':{ *p = 's'; + (IGNORED) fprintf(log_file, fmt, job); break;} + case '2':{ *p = 'd'; + (IGNORED) fprintf(log_file, fmt, page); break;} + case '3':{ *p = 's'; + (IGNORED) fprintf(log_file, fmt, font); break;} + case '%':{ *p = 'c'; + (IGNORED) fprintf(log_file, fmt, '%'); break;} + default:{ job[ (int) strlen((char *) job) ] ='.'; return;} + } + p = ++ch; + }else ch++; +} } +>>> + + + +\<print segment of templet\><<< +*ch = '\0'; (IGNORED) fprintf(log_file, "%s", p); +*(ch++) = '%'; +>>> + +The jobname var contains a period at the end, removed +temporarily for the script. The default case above should have been +an error, or at least a warning. + + + +\<get format of output\><<< +p=fmt; *(p++) = '%'; +if( *ch == '\0' ){ job[ (int) strlen((char *) job) ] ='.'; return; } +while( *ch != '%' ){ *(p++) = *(ch ++); } +*(p+1) = '\0'; +>>> + + + +\Verbatim + + > Instead of a single-line script + + > scall convert %1 %2 %3\nif errorlevel 1 goto end + + > you are allowed also to have multi-lines scripts + + > scall convert %1 %2 %3 + > sif errorlevel 1 goto end + + > Would this work? If '\n' is a superior solution I + > see no problems implementing it. + + Yes, this works fine for the "if errorlevel" problem. However, I have +found out in the meantime (RTMF is always a good idea ;-) that the +emTeX driver can create _all_ pcx files in one run, giving them names +like out01.gif, out02.gif, ... (or out001.gif, out002.gif, ... - it +depends on command line options). Display has a similar option. This +would significantly reduce the total conversion time, so I'm inclined to +use this option. (I think it may even outweigh the advantage of not +recreating the gifs after the b line, although I may be able to +implement that anyway with a little trickery). Since DOS has no way to +increase counters, I'd like to see the page numbers tex4ht gives also as +"01" (or "001"), etc. This would make it easy for me to use the emTeX +functionality. I've implemented this in tex4ht.c by changing the page +number format from %d to %03d. I assume this won't break anything else? + + + > I didn't get the idea. + + The emTeX dvidot driver, when given an output filename like 'out???', +creates an output file for each page in the dvi file in one run, named +out001, out002, out003, etc. If the page numbers tex4ht produces are of +the same form (001 instead of 1), I can simply append them to 'out' like +this: out%2. This makes it easier to process the created files further. + + > The change is in the following line? + + > case '2':{ (IGNORED) fprintf(log_file, "%d", page); break;} + + Yes. + + > Is %03d the same as %0.3d? If not, what is the difference? + + For integers, yes; it is also the same as %.3d. I just prefer the +first form, as it makes more sense to me (things after the dot are +called the precision specifier, and I don't want to specify precision +but field width). +\EndVerbatim + +\SubSection{Script for Translation into Gifs} + + +\<h-defines\><<< +#ifndef LGPIC +#define LGPIC "--- needs --- %%1.idv[%%2] ==> %%3 ---\n%" +#endif +>>> + + +\<vars\><<< +static U_CHAR *font_gif = NULL; +>>> + + +\<get gif script from com ln\><<< +font_gif = p+2; +>>> + + + +\<get from tex4ht.env file\><<< +font_gif = (char *) get_script(font_gif,LGPIC,'s'); +`<inser percent-ch at end of s-script`> +>>> + + +\<inser percent-ch at end of s-script\><<< +{ int n; + n = (int) strlen((char *) font_gif); + if( font_gif[n-1] != '%' ){ font_gif[n] = '%'; font_gif[n+1] = '\0'; } +} +>>> + + +\SubSection{Script lg file Seperator} + + +Separates general picturs from symbols. + +\<h-defines\><<< +#ifndef LGSEP +#define LGSEP "--- characters ---\n" +#endif +>>> + + +\<vars\><<< +static U_CHAR *begin_char_gif = NULL; +>>> + + + +\<get start char-gif from com ln\><<< +begin_char_gif = p+2; +>>> + + + +\<get from tex4ht.env file\><<< +begin_char_gif = (char *) get_script(begin_char_gif,LGSEP,'b'); +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Default Format for Pictures} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<h-defines\><<< +#ifndef LGTYP +#define LGTYP ".png" +#endif +>>> + + +\<vars\><<< +static U_CHAR *gif = NULL; +>>> + + + +\<get gif-type from com ln\><<< +gif = p+2; +>>> + +In the extension name we don't want the line break at the end. + +\<get from tex4ht.env file\><<< +gif = (char *) get_script(gif,LGTYP,'g'); +{ int n; + n = (int) strlen((char *) gif) - 1; + if( gif[n] == '%' ){ gif[n] = '%'; } + else if( gif[n] == '\n' ) { gif[n] = '\0'; } +} +>>> + + + + + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Encoding for Dos Font Names} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +We set font name + mag (2 chars) + ch number (2 ch). If the length is +no greater than 8, we are done. Otherwise, we take the first n-2 +characters and map them to a string of length 4. They are the most +stable in the names, so they minimize replacements. + +\<header functions\><<< +`% +#ifdef DOS_GIF_FILE +`% +static void dos_gif_file( ARG_III(char *, int, int) ); +`% +#endif +`% +>>> + +\<functions\><<< +`% +#ifdef DOS_GIF_FILE +`% +`[ +static void dos_gif_file(str, mag, design_ch) + U_CHAR *str`; + int mag`; + int design_ch + +;{ int n, m, i; + struct gif_file_rec * p, * q; + U_CHAR *ch; + m = n = (int) strlen((char *) str); + if( n > 4 ){ + `<p = prefix of font file`> + if( p == NULL ){ `<p = new prefix font file`> } + gif_file = p; + for( n=0; n<4; n++ ) str[n] = xeh[(int)(*(p->code + n))]; + } + str[n++] = xeh[mag<16? 0: mag / 16]; + str[n++] = xeh[mag % 16]; + str[n++] = xeh[design_ch<16? 0: design_ch / 16]; + str[n++] = xeh[design_ch % 16]; + str[n] = '\0'; +} +`% +#endif +`% +>>> + + + +We keep collisions table to ensure agains collisions. We do it in +circular linked list so that last visited in previous turn will be the +first to be visited now. The prefix, and its suggested + +\<types\><<< +`% +#ifdef DOS_GIF_FILE +`% +struct gif_file_rec{ + U_CHAR code[4]; + U_CHAR *name; + struct gif_file_rec *next; }; +`% +#endif +`% +>>> + +\<vars\><<< +`% +#ifdef DOS_GIF_FILE +`% +static struct gif_file_rec * gif_file = (struct gif_file_rec *) 0; +`% +#endif +`% +>>> + +\<p = prefix of font file\><<< +if( (p = gif_file) != NULL ){ + while( TRUE ){ + if( eq_str( str, p->name ) ) break; + if( (p = p->next) == gif_file ){ p = NULL; break; } +} } +>>> + + + + + + +\<p = new prefix font file\><<< +p = m_alloc(struct gif_file_rec, 1); +`<get tentative prefix replacement`> +`<adjust prefix replacement`> +(IGNORED) printf("\nRenaming ``%s____%s' to ``%c%c%c%c____%s'\n", + str, gif, + xeh[(int)(ch[0])], xeh[(int)(ch[1])], + xeh[(int)(ch[2])], xeh[(int)(ch[3])] + , gif); +p->name = m_alloc(char,m+1); +(IGNORED) strcpy((char *) p->name, (char *) str ); +if( gif_file ){ p->next = gif_file->next; gif_file->next = p; } + else p->next = p; +>>> + + +We choose the scheme `sum(char codes of str) / 4' to find a number i, +and then we cycle around hex in jumps of i to choose four characters +not starting with digit. + +\<get tentative prefix replacement\><<< +for(i=str[n]; n; ){ i+=str[--n]; if( i > (INT_MAX / 8) ) i/=2; } +if( (n=i % BASE) <10 ) n+= 10 + i%(BASE-20); +*(ch = p->code)= n; n += i; +ch[1] = n%BASE; n += i; +ch[2] = n%BASE; n += i; +ch[3] = n%BASE; +>>> + + +To allow for adjustments, we srtoe indexes of xeh, and not the +characters themselve. +We allow $BASE^3$ options of adjustments!!! + +\<adjust prefix replacement\><<< +if( gif_file ){ + q = gif_file->next; + while( TRUE ){ + if( (*(q->code) == *ch) && (*(q->code+1) == ch[1]) && + (*(q->code) == ch[2]) && (*(q->code+2) == ch[3]) ){ + ch[3] ++; ch[2] += ch[3]/ BASE; ch[3] = ch[3] % BASE; + ch[1] += ch[2]/ BASE; ch[2] = ch[2] % BASE; + ch[1] = ch[1] % BASE; + q = gif_file; + } else if( q == gif_file ) break; + q = q->next; +} } +>>> + +Instead of hex we take xeh. + + +\<defines\><<< +#define BASE 36 +>>> + +\<vars\><<< +`% +#ifdef DOS_GIF_FILE +`% +static U_CHAR xeh[]="0123456789abcdefghijklmnopqrstuvxyz"; +`% +#endif +`% +>>> + + + +\SubSection{Other} + +\`'<<' is NOT a safe operation, beyond char size, for transporting across platforms. + +\<defines\><<< +#define store_bit_I(ch,i) ch[(i)/8]|=(1<<((i)%8)); +#define store_bit_Z(ch,i) ch[(i)/8]&=~(1<<((i)%8)) +#define add_bit(ch,i,b) ch[(i)/8] |= ((b) << ((i)%8)) +#define get_bit(ch,i) ((ch[(i)/8] >> ((i)%8)) & 1) +>>> + + + +%#define store_bit(ch,i,b) if(b){ ch[(i)/8]|=(1<<((i)%8));}\ +% else ch[(i)/8]&=~(1<<((i)%8)) + + + +\<header functions\><<< +static void put_alt_ch( ARG_II( int, BOOL) ); +>>> + +\<functions\><<< +`[ +static void put_alt_ch(chr,ch_str_flag) + int chr`; + BOOL ch_str_flag +;{ + if( !ch_str_flag ) put_char( chr ); + else if( chr > 0 ){ `<put htf char string`> } +} +>>> + + +The \`'gif_ch' is true when we put the character outside of +\`'\special{t4ht|}...\special{t4ht|}', and is false inside that range. +Within that range, used in ALT's, we want to eliminate the html +comamnds \`'<...>' and the delimiter characters \`'"'. + +\<put htf char string\><<< + unsigned U_CHAR * p; +p = font_tbl[cur_fnt].str[chr-1]; +if( gif_ch ) print_f( (char *) p ); `% /*new*/`% +else while( *p ){ + switch( *p ){ + case '<': { while( *p && (*p != '>') ) p++; break; } + case '>': + case '"': { p++; break; } + case '\'': { p++; break; } + default: { put_char( (int) *p ) ; p++; } +} } +>>> + +% case '&': { alt_ch_length = strlen((char *) p); } + +%\<vars\><<< +%static int alt_ch_length = 0; +%>>> + + +\<vars\><<< +static BOOL gif_ch = TRUE; +static int design_ch = 0; +>>> + + + +\Section{Css Trace on Characters} + +\`'\Configure{characters}{<SPAN\:newlnch NAME="}{">}{</SPAN>} +{<IMG SRC="}{"ALT="}{"NAME="}{">}' + + + +\<css for characters\><<< + int n, code; + U_CHAR *p, *q; +code = get_char(); +n = 1 + ((--special_n>254)? 254 : special_n); +q = p = m_alloc(char, (int) n); +while( special_n > 254 ){ (void) get_char(); special_n--; } +while( special_n-- ) { *(q++) = get_char(); } +*q = '\0'; q = p; +switch ( code ){ + case '8': { pause_style--; break; } + case '9': { pause_style++; break; } + case '-': { default_font = font_tbl[cur_fnt].num; + base_font_size = font_tbl[cur_fnt].scale / 100; + break; } + case '+': { default_font = -1; break; } + case '%': { `<insert font size`> break; } + case '=': { `<insert css name of ch`> break; } + case '|': { `<record string for htf class`> break; } + case ',': { `<don't report next htf class to lg`> break; } + default: { warn_i_int( 36, code); } +} +span_on = span_name_on && !pause_style; +if( q ) free((void *) q); +>>> + +Since htf fonts are shred within tex fonts, and since they can easily +be modified by scripts in the output html files, changes of their classes +from within the 4ht files is not supported. + + + +By taking integer for \`'pause_style' we allow for nested pausing of fonts. + + + +\<vars\><<< +static int pause_style = 0, default_font = -1, base_font_size=6533; +static BOOL + span_name_on = FALSE, + span_on = FALSE; +>>> + + + + + + + + +\SubSection{4: Src Prefix} + + +\<record img-srcOUT\><<< +q = img_src; img_src = p; +>>> + +\<varsOUT\><<< +static U_CHAR * img_src; +>>> + +\<main's initOUT\><<< +img_src = m_alloc(char, (int) 12); +(IGNORED) strcpy((char *) img_src, "<img \nsrc=\"" ); +>>> + + +\<<IMG SRC="...\><<< +p= gif_open[gif_flag]; +if( p ) +if( *p ){ + print_f(p); (IGNORED) strcpy((char *) str, (char *) font_tbl[cur_fnt].name); + mag = (int) ((double) font_tbl[cur_fnt].scale / + font_tbl[cur_fnt].design_sz * 10 ); + `<insert gif symbol to html file`> + print_f(str); + add_bit( font_tbl[cur_fnt].gif_on, r_ch, 1 ); +} +>>> + + +\SubSection{5: Alt Prefix} + + + +\<record img-altOUT\><<< +q = img_alt; img_alt = p; +>>> + +\<varsOUT\><<< +static U_CHAR * img_alt; +>>> + +\<main's initOUT\><<< +img_alt = m_alloc(char, (int) 7); +(IGNORED) strcpy((char *) img_alt, "\"alt=\"" ); +>>> + + + +\<..."ALT="...\><<< +p = gif_alt[gif_flag]; +if( p ) + if( *p ){ + print_f(p); put_alt_ch(chr,ch_str_flag); +} +>>> + + +\SubSection{6: Img-CLASS Prefix} + + + + +\<..."CLASS="family...\><<< +p = gif_class[gif_flag]; +if( p ) + if( *p ){ + (IGNORED) fprintf(cur_o_file, p, + font_tbl[cur_fnt].family_name); } +>>> + + + + + + + +%-------------------------------------- + + +\SubSection{s: Img-CLASS Size} + + + + + + +\<...gif font size...\><<< +p = gif_size[gif_flag]; +if( p ) + if( *p ){ + (IGNORED) fprintf(cur_o_file, p, + font_tbl[cur_fnt].font_size); } +>>> + + + + +\SubSection{m: Img-CLASS Magnitude} + + + + + +\<...gif font mag...\><<< +p = gif_mag[gif_flag]; +if( p ) + if( *p && (font_tbl[cur_fnt].mag != 100) ){ + (IGNORED) fprintf(cur_o_file, p, font_tbl[cur_fnt].mag); +} +>>> + + + + + +\SubSection{o: Img-CLASS Ord} + + +\<...gif sym ord...\><<< +p = gif_ord[gif_flag]; +if( p ) + if( *p ){ + (IGNORED) fprintf(cur_o_file, p, ch); +} +>>> + + +%-------------------------------------- + +\SubSection{7: End Image} + + + + + +\<..."/IMG>\><<< +p = gif_end[gif_flag]; +if( p ) + if( *p ){ print_f( p ); } +>>> + + + +\SubSection{Htf-based Classes} + + + +\<record string for htf class\><<< +{ int bad_str, m; + U_CHAR ch, *t[`<n spans`>], err_str[256]; +bad_str=`<n spans-1`>; (IGNORED) strcpy((char *) err_str, (char *) p); +if( n>`<n spans+2`> ){ + m = 100*( *p-'0' ) + 10*( *(p+1)-'0' )+ *(p+2)-'0'; + if( (m>-1) && (m<256) ){ + ch = *(p + 3); t[0]=p; + while( (*p = *(p+4)) != '\0' ){ + if( ch == *p ){ *p = '\0'; + if( bad_str-- > 0 ) t[`<n spans-1`> - bad_str] = p+1; + } + p++; + } } + if( !bad_str ){ + if( m==0 ){ span_name_on = n>`<n spans+3`>; } + q = span_open[m]; span_open[m] = t[0]; + span_name[m] = t[1]; span_size[m] = t[2]; + span_mag[m] = t[3]; span_ord[m] = t[4]; + span_ch[m] = t[5]; end_span[m] = t[6]; + gif_id[m] = t[7]; + if( not_notify ) { + store_bit_I( class_on, m ); + not_notify = FALSE; + } else store_bit_Z( class_on, m ); + } +} +if( bad_str ){ warn_i_str(37,err_str); } +} +>>> + + + + + +\<don't report next htf class to lg\><<< +not_notify = TRUE; +>>> + +\<vars\><<< +static BOOL not_notify = FALSE; +>>> + + +\<n spans\><<< +8>>> +\<n spans-1\><<< +7>>> +\<n spans+2\><<< +10>>> +\<n spans+3\><<< +11>>> + + + +\<vars\><<< +static U_CHAR * span_name[256], * span_open[256], * span_size[256], + * span_mag[256], * span_ch[256], * end_span[256], + * span_ord[256], * gif_id[256]; +static U_CHAR class_on[32]; +>>> + + +\<main's init\><<< +{ int i; i=256; while( i-- ) { + span_name[i] = span_open[i] = span_size[i] = + span_mag[i] = span_ch[i] = end_span[i] = + span_ord[i] = gif_id[i] = NULL; + if( (i>0) && !(i%2) ) { store_bit_Z( class_on, i ); } + else { store_bit_I( class_on, i ); } + } +} +>>> + + + +\<defines\><<< +#define gif_open span_open +#define gif_alt span_name +#define gif_class span_size +#define gif_size span_mag +#define gif_mag span_ord +#define gif_ord span_ch +#define gif_end end_span +>>> + + + +%\<main's init\><<< +%{ int i; i=256; while( i-- ) { htf_class[i] = 0 ; } } +%>>> + +\`'0': character without decoration; \`'1' gif +without decoration. Even numbers +(\`'...0') are reserved for ch with decoration, and odd numbers +(\`'...1') are for gifs with decoration. + + + +A character template takes the form: +open + family-format + +size-format + mag-format + ord + close +after-font-info; The delimiter +can be +, or any other character. + + + +\<put char(chr)\><<< +`<open output file`> +`<ensure for chr`> +if( span_on ){ + `<open for chr`> + `<font-family of chr`> + `<font-size of chr`> + `<font-mag of chr`> + `<ord of chr`> + `<close for chr`> +} +put_char(chr); +if( span_on ){ + `<end for chr`> +} +>>> + + + +\<put string-char(chr)\><<< +`<ensure for chr`> +if( span_on ){ + `<open for chr`> + `<font-family of chr`> + `<font-size of chr`> + `<font-mag of chr`> + `<ord of chr`> + `<close for chr`> +} +put_alt_ch(chr,ch_str_flag); +if( span_on ){ + `<end for chr`> +} +>>> + +\<ensure for chr\><<< +if( gif_flag && !get_bit( class_on, gif_flag ) ) { + notify_class_info(gif_flag); + store_bit_I( class_on, gif_flag ); +} +>>> + + + + +\<open for chr\><<< +if( span_open[gif_flag] ) + if( *span_open[gif_flag] ){ + print_f( span_open[gif_flag] ); +} +>>> + +\<end for chr\><<< +if( end_span[gif_flag] ) + if( *end_span[gif_flag] ){ + print_f( end_span[gif_flag] ); +} +>>> + + + +\<close for chr\><<< +if( span_ch[gif_flag] ) + if( *span_ch[gif_flag] ){ + print_f( span_ch[gif_flag] ); +} +>>> + + +\<font-family of chr\><<< +if( span_name[gif_flag] ) + if( *span_name[gif_flag] ){ + (IGNORED) fprintf(cur_o_file, span_name[gif_flag], + font_tbl[cur_fnt].family_name); +} +>>> + + + +\<font-size of chr\><<< +if( span_size[gif_flag] ) + if( *span_size[gif_flag] ){ + (IGNORED) fprintf(cur_o_file, span_size[gif_flag], + font_tbl[cur_fnt].font_size); +} +>>> + + +\<font-mag of chr\><<< +if( span_mag[gif_flag] ) + if( *span_mag[gif_flag] ){ + (IGNORED) fprintf(cur_o_file, span_mag[gif_flag], + font_tbl[cur_fnt].mag); +} +>>> + + +\<ord of chr\><<< +if( span_ord[gif_flag] ) + if( *span_ord[gif_flag] ){ + (IGNORED) fprintf(cur_o_file, span_ord[gif_flag], chr); +} +>>> + + + + + +\SubSection{Font Properties} + +\<insert font size\><<< + int f; +f = 0; while( *p ){ f = 10*f + *(p++) - '0'; } +`<open output file`> +(IGNORED) fprintf(cur_o_file, "%d", + (font_tbl[cur_fnt].scale / base_font_size - 100) * f / 100 +100 + ); +>>> + +\<insert css name of ch\><<< +`<open output file`> +(IGNORED) fprintf(cur_o_file, "%s", font_tbl[cur_fnt].name); +if( font_tbl[cur_fnt].mag != 100 ){ + (IGNORED) fprintf(cur_o_file,"_%d", font_tbl[cur_fnt].mag); +} +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Chapter{Cascade Style Sheets} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%% +\Section{Command Line} +%%%%%%%%%%%%%%%%%% + + + +\<get cascade style sheet data\><<< +struct css_ext_rec * css = m_alloc(struct css_ext_rec, 1);; +css->name = p + 2; +css->next = css_ext; +css_ext = css; +>>> + +\<post scan comm ln args\><<< +if( css_ext == (struct css_ext_rec *) 0 ){ + struct css_ext_rec * css = m_alloc(struct css_ext_rec, 1);; + css->name = css_default; + css->next = css_ext; + css_ext = css; +} +>>> + +\<main's vars\><<< +static struct css_ext_rec * css_ext = (struct css_ext_rec *) 0; +static char css_default[] = "4cs"; +>>> + +\<types\><<< +struct css_ext_rec{ char* name; + struct css_ext_rec *next; }; +>>> + + +%%%%%%%%%%%%%%%%%% +\Section{Retrieve Data} +%%%%%%%%%%%%%%%%%% + + + +\<get css entries\><<< +{ static struct css_ext_rec * search_css_ext; + for( search_css_ext = css_ext; + search_css_ext != (struct css_ext_rec *) 0; + search_css_ext = search_css_ext->next ){ + int css_name_n = (int) strlen((char *) new_font.name ); + char * css_file_name = m_alloc(char, css_name_n + 1); + (IGNORED) strcpy((char *) css_file_name, (char *) new_font.name); + for( ; css_name_n; css_name_n-- ){ + FILE* file; + css_file_name[css_name_n] = '\0'; + `<file = .css file`> + } + free((void *) css_file_name); +} } +>>> + +\<file = .css file\><<< +{ U_CHAR name[256]; + (IGNORED) sprintf(name, "%s.%s", css_file_name, + search_css_ext->name); + `<search file in htf locations`> + if( file != NULL ){ + `<write css file to lg file`> + (IGNORED) fclose(file); break; + } +} +>>> + + + +%%%%%%%%%%%%% +\Section{Copy CSS File} +%%%%%%%%%%%%% + + + + +\<write css file to lg file\><<< +`<check visited`> +if( !is_visited ){ + `<mark visited`> + while( 1 ){ + int ch; + do{ + ch = (int) getc(file); + } while ( (ch == ' ') || (ch == '\n') || (ch == '\t') ); + if( ch == EOF ){ break; } + do{ + (void) putc( ch, log_file ); + ch = (int) getc(file); + } while ( (ch != '\n') && (ch != EOF) ); + (void) putc( '\n', log_file ); + if( ch == EOF ){ break; } +} } +>>> + +%%%%%%%%%%%%% +\Section{Duplicates Avoidance} +%%%%%%%%%%%%% + + + +\<scan fonts vars\><<< +struct visited_file_rec * visited_file = + (struct visited_file_rec *) 0; +>>> + +\<end loading fonts\><<< +while( visited_file != (struct visited_file_rec *) 0 ){ + struct visited_file_rec * v = visited_file; + visited_file = visited_file->next; + free((void *) v->name); + free((void *) v); +} +>>> + + +\<mark visited\><<< +struct visited_file_rec * v = m_alloc(struct visited_file_rec, 1); +v->name = m_alloc(char, (int) strlen((char *) name ) + 1 ); +(IGNORED) strcpy((char *) v->name, (char *) name); +v->next = visited_file; +visited_file = v; +>>> + +\<check visited\><<< +BOOL is_visited = FALSE; +struct visited_file_rec * v = visited_file; +while( v != (struct visited_file_rec *) 0 ){ + if( eq_str(v->name, name) ){ + is_visited = TRUE; break; + } + v = v->next; +} +>>> + + +\<types\><<< +struct visited_file_rec{ char *name; + struct visited_file_rec *next; }; +>>> + + + + +%%%%%%%%%%%%%%%%%%%%%% +\Chapter{Accents} +%%%%%%%%%%%%%%%%%%%%%% + +\Section{Htf Font Info} + +Each htf font has between 2 to 4 fields per entry. The first field is +the textual representation, the second is the textual and pictorial +flags and decorations, the third is an the accent code, and the fourth +is a pointer into an accented code table (tex4ht.htf). + + +font.htf: + +\Verbatim +'text-rep' 'text/pic-deco' 'accent-code' 'pointer to tex4ht.htf' +\EndVerbatim + + +The accent code uses universaly agreed upon codes for accent symbols. +For instance, 18 for \'=\`=, and 94 for \'=\^=. 0 signify no pointer. + +The accented code uses universaly agreed upon codes for accented +symbols. We assume a unicode code-based system, but deviate from +it when it is convinient. + + +tex4ht.c makes move the third and fourt entries of each font into arrays, +and puts into the entries index-pointers to the array. By doing so, we can +allocate just one byte to an entry. + + +\Draw \ArrowHeads(1) +\DrawRect(80,-150) +\Move(5,-20) + +{\Do(1,10){\Move(0,-10) +{ \PaintRect(10,3) +\Move(20,0) \PaintRect(10,3) +\Move(20,0) \PaintRect(10,3) +\Move(20,0) \PaintRect(10,3)}} +} + +\PaintRect(10,3) +\Move(20,0) \PaintRect(10,3) +\Move(20,0) \PaintRect(10,3)\FcNode(a) +\Move(20,0) \PaintRect(10,3)\FcNode(a2) + + +\MoveTo(100,-140) {\Move(5,10) \FcNode(b) \ArrowHeads(1) \Edge(a,b)} +\Do(1,4){\DrawRect(20,10) \Move(20,0)} + +\MoveTo(100,-100) + {\Move(5,10) \FcNode(b) \ArrowHeads(1) \Edge(a2,b)} +\Do(1,4){\DrawRect(20,10) \Move(20,0)} + +\MoveTo(130,-30) {\Move(-5,-5) \FcNode(b) + \Move(15,0) \Text(--A--) + \Move(35,0) \Text(--\string^--) + {\Move(15,25) \Text(--\^A--)} + \Move(35,0) \Text(--\string^\string^--) + {\Move(15,25) \Text(--$\hat {\hat A}$--)} + } +\Do(1,4){\DrawRect(20,10) \Move(0,-10)} + +\MoveTo(150,-35) +{\Move(-20,0)\FcNode(a) \Move(-20,-60) \FcNode(b) \VHEdge(b,a)} +\Do(1,4){\FcNode(a) \Move(15,0) \FcNode(b) + {\Edge(a,b)} \Move(0,-5) \DrawRect(20,10) + {\Move(10,10)\FcNode(a) \Move(0,15) \FcNode(b) {\Edge(a,b)} + \DrawRect(20,10)} + \Move(20,5) +} + + + + + +\EndDraw + + + + + + +The accented code matrix tex4ht.htf is the closest file to the font on +the directory path from the root. Different paths may employ a +different tex4ht.htf accent tables. An +(accent-code,accented-code) pair maps to accented-code in the table, +or the maping is undefined. Each accented-code in the matrix hold +textual representation. + +\<entries for html chars in font-tbl\><<< +unsigned U_CHAR *accent, *accented; +unsigned int *accent_array, *accented_array, accent_N, accented_N; +>>> + +\<initiate htf accents\><<< +new_font.accent = m_alloc(unsigned char, n_gif ); +new_font.accented = m_alloc(unsigned char, n_gif ); +new_font.accent_array = (unsigned int *) 0; +new_font.accented_array = (unsigned int *) 0; +new_font.accent_N = new_font.accented_N = 0; +for( i=n_gif; i--; ) { + new_font.accent[i] = new_font.accented[i] = 0; +} +>>> + + +\<scan htf accent\><<< +ch1 = 0; +while( ((ch = (int) get_html_ch(file)) != del) ){ + if( (ch < '0') || (ch > '9') ){ warn_i_int(48,i); break; } + ch1 = ch1 * 10 + ch - '0'; } +new_font.accent_array = new_font.accent_N++? + (unsigned int *) r_alloc((void *) new_font.accent_array, + (size_t) (new_font.accent_N * sizeof(unsigned int))) + : m_alloc(unsigned int, 1); +new_font.accent_array[new_font.accent_N - 1] = ch1; +new_font.accent[i] = new_font.accent_N; +>>> + + +\<scan htf accented\><<< +ch1 = 0; +while( ((ch = (int) get_html_ch(file)) != del) ){ + if( (ch < '0') || (ch > '9') ){ warn_i_int(48,i); break; } + ch1 = ch1 * 10 + ch - '0'; } +new_font.accented_array = new_font.accented_N++? + (unsigned int *) r_alloc((void *) new_font.accented_array, + (size_t) (new_font.accented_N * sizeof(unsigned int))) + : m_alloc(unsigned int, 1); +new_font.accented_array[new_font.accented_N - 1] = ch1; +new_font.accented[i] = new_font.accented_N; +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Integrated accents} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Remote Accents} +%%%%%%%%%%%%%%%%%%%%%%%% + +If the accent character is for text (\''\accent'), we'll be looking +for the next character to be the accented character. If the accent +character is for math (\''\mathaccent'), we'll be looking for the next +group of characters (i.e., subformula) to be the accented. If the +subformula consists of a single character, we probably should assume +an accented character instead of an accented subformula. + + +\List{*} +\item \''\special{t4ht*\string^t}'---requests to consume the +next character, tailored to be placed just before an \''\accent'. In addition, +if a template exists for text accents, the family-name and +character-code of the accent are printed before the accented +parameter together with the first three parts of the template. In such +a case, the fourth part of the template is printed after the content. +\item +\''\special{t4ht*\string^t#1 #2 #1 #3 #1 #4 #1 #5 #1 #6}'---provides +template consisting of four parts, where \''#1' is assumed to +be a distinguished character separating the components. If the +separators appears only twice or three times, the template is +annihilated. +\item \''\special{t4ht*\string^m...}'---Variants of the above cases +for \''\mathaccent'. However, the fourth part of the template is +ignored, and assumed to be requested througth a +\''Send{EndGroup}{1}{...}' (i.e., \''\special{t4ht\string~>1...}'). +\EndList + + +\SubSection{Open Accent} + +\<accent specials\><<< +special_n--; +switch ( get_char() ){ + case 't': { if( special_n ){ + `<text accent template`> + } else { `<text accent`> } + break; + } + case 'm': { if( special_n ){ + `<math accent template`> + } else { `<math accent`> } + break; + } + case 'a': { `<accented template`> + break; + } + case 'i': { `<accenting template`> + break; + } + default: { `<consume unused specials`> } +} +>>> + + + +A accent is a character from a given font. Given a content to be +accented, the text/math accent marks it \`'#1 font #2 char-no #3 +content #4' according to the accent/mathaccent template. Each +character in the content is marked by \`'#1 font #2 char-no #3 +character #4' according to the accented template. + + + +Text accent can be on empty content or on character, and the accent +itself is empty if it consists of a character code greater than 127. + Math accent is +placed on the center of a formula. + +\<text accent\><<< +needs_accent_sym = TRUE * 2; +>>> + +\<math accent\><<< +needs_accent_sym = TRUE; +>>> + +\<accented = true\><<< +needs_accented_sym++; +>>> + + +The \''\special' tells tex4ht where the accent starts, and tex4ht +consumes the following character for a accent. At that place, tex4ht +also place the opening tag of the element. + + + +\<pre accent symbol\><<< +if( in_accenting ){ + `<post accent symbol`> +} else if( `<is accent char?`> ){ + if( needs_accent_sym ){ + BOOL needs_end_accent; + needs_end_accent = (needs_accent_sym == 2 * TRUE); + if( needs_end_accent && t_accent_template ){ + (IGNORED) fprintf(cur_o_file, "%s%s%s%d%s%d%s", + t_accent_first, font_tbl[cur_fnt].family_name, + t_accent_second, ch, t_accent_third, + font_tbl[cur_fnt].accent[ch]? + font_tbl[cur_fnt].accent_array[font_tbl[cur_fnt].accent[ch]-1] + : 0, + t_accent_fourth); + } else if( m_accent_template ){ + (IGNORED) fprintf(cur_o_file, "%s%s%s%d%s%d%s", + m_accent_first, font_tbl[cur_fnt].family_name, + m_accent_second, ch, m_accent_third, + font_tbl[cur_fnt].accent[ch]? + font_tbl[cur_fnt].accent_array[font_tbl[cur_fnt].accent[ch]-1] + : 0, + m_accent_fourth); + } + if( i_accent_template ){ + (IGNORED) fprintf(cur_o_file, "%s", i_accent_first); } + in_accenting = TRUE; + } +} +>>> + + +\<post accent symbol\><<< + long int width; +if( i_accent_template ){ + (IGNORED) fprintf(cur_o_file, "%s", i_accent_second); } +needs_end_accent = (needs_accent_sym == 2 * TRUE); +if( needs_end_accent && t_accent_template ) +{ `<accented = true`> } +else if( m_accent_template ) +{ `<accented = true`> stack[stack_n-1].accented = TRUE; } +needs_accent_sym = FALSE; +width = (INTEGER)( `<(double) char_width( ch )`> ); +if( needs_end_accent ){ needs_end_accent = x_val + 9 * width / 10; } +in_accenting = FALSE; +>>> + +\<main's vars\><<< +BOOL in_accenting; +>>> + +\<main's init\><<< +in_accenting = FALSE; +>>> + +The following needs to be fixed for cases that ch is greater than 127. + +\<is accent char?\><<< +needs_accent_sym && (ch < 128) +>>> + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Closure for Text Accent} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\<end text accent\><<< +if( needs_end_accent && t_accent_template ){ + `<end accented span`> + (IGNORED) fprintf(cur_o_file, "%s", t_accent_fifth); + needs_end_accent = FALSE; `<exit text accented`> +} +>>> + + + + + + + +The following in needed for cases of text-accents on empty content, +immeddiately followed by a character (e.g., \`'\^{}Xx'). + +\<set begin accents\><<< +if( x_val > needs_end_accent ){ + `<end text accent`> +} +>>> + + +The following takes care of closing a text accent after a character. + +\<set end accents\><<< +`<end text accent`> +>>> + +%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Tailoring} +%%%%%%%%%%%%%%%%%%%%%% + +before-family-name, between-family-char-number, after char-number + +\<text accent template\><<< +(IGNORED) get_open_accent(&t_accent_template, + &t_accent_first, &t_accent_second, + &t_accent_third, &t_accent_fourth, + &t_accent_fifth, &special_n); +>>> + +\<math accent template\><<< +(IGNORED) get_open_accent(&m_accent_template, + &m_accent_first, &m_accent_second, + &m_accent_third, &m_accent_fourth, + &m_accent_fifth, &special_n); +>>> + + + + +\<vars\><<< +static BOOL needs_accent_sym = FALSE, needs_end_accent = FALSE; +static char * t_accent_template = (char *) 0, + * t_accent_first, * t_accent_second, + * t_accent_third, * t_accent_fourth, * t_accent_fifth, + * m_accent_template = (char *) 0, + * m_accent_first, * m_accent_second, + * m_accent_third, * m_accent_fourth, * m_accent_fifth; +>>> + + + + +\<header functions\><<< +static void get_open_accent( + ARG_VII(char**, char**, char**, char**, char**, char**, long int*)); +>>> + +\<functions\><<< +`[ +static void get_open_accent(all,first,second,third,fourth,fifth,n) + char **all`; + char **first`; + char **second`; + char **third`; + char **fourth`; + char **fifth`; + long int *n +;{ char *p, *q; + int i; + if( *all ){ free((void *) *all); } + *all = p = get_str( (int) *n ); *n=0; + i = 2; + *first = q = p + 1; + while ( TRUE ){ + if( *q == *p ){ + *q = '\0'; + switch( i ){ + case 2:{ *second = q+1; break; } + case 3:{ *third = q+1; break; } + case 4:{ *fourth = q+1; break; } + case 5:{ *fifth = q+1; break; } + } + if( i++ == 5 ){ break; } + } else if( !*q ){ + free((void *) *all); *all = (char *) 0; break; + } + q++; +} } +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Mark Accented Content} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\<mark accented ch\><<< +if( a_accent_template && needs_accented_sym ){ + (IGNORED) fprintf(cur_o_file, "%s%s%s%d%s%d%s", + a_accent_first, font_tbl[cur_fnt].family_name, + a_accent_second, ch, a_accent_third, + font_tbl[cur_fnt].accented[ch]? + font_tbl[cur_fnt].accented_array[font_tbl[cur_fnt].accented[ch]-1] + : 0, + a_accent_fourth); +} +>>> + + +\<end mark accented ch\><<< +if( a_accent_template && needs_accented_sym ){ + (IGNORED) fprintf(cur_o_file, "%s", a_accent_fifth); +} +>>> + +Accents can be embedde, for instance, \`'\hat{a\hat b}'. Hence, +\''needs_accented_sym' is treated as a number. + + + +The math accented end at the end of the group, sent there by +\`'\special{t4ht~>...}' in the sty file. + +\<exit math accented\><<< +needs_accented_sym--; +>>> + + +\<exit text accented\><<< +needs_accented_sym--; +>>> + +\<accented template\><<< +(IGNORED) get_open_accent(&a_accent_template, + &a_accent_first, &a_accent_second, + &a_accent_third, &a_accent_fourth, + &a_accent_fifth, &special_n); +>>> + +\<vars\><<< +static BOOL needs_accented_sym = 0; +static char * a_accent_template = (char *) 0, + * a_accent_first, * a_accent_second, + * a_accent_third, * a_accent_fourth, * a_accent_fifth; +>>> + + + +\<accenting template\><<< +(IGNORED) get_open_accent(&i_accent_template, + &i_accent_first, &i_accent_second, + &i_accent_third, &i_accent_fourth, + &i_accent_fifth, &special_n); +>>> + +\<vars\><<< +static char * i_accent_template = (char *) 0, + * i_accent_first, * i_accent_second, + * i_accent_third, * i_accent_fourth, * i_accent_fifth; +>>> + +\`'* i_accent_second, + * i_accent_third, * i_accent_fourth;' are dummy +provided for consistency. + + + + +\<BOOl stack accented\><<< +accented +>>> + +\<end math accented\><<< +if( stack[stack_n].accented ){ + `<exit math accented`> + stack[stack_n].accented=FALSE; +} +>>> + +\<init end math accented\><<< +stack[stack_n].accented = FALSE; +>>> + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Chapter{Math Classes for Symbols} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Tex assignes class numbers 0--7 to the atoms of math formulas: +0--ordinary symbol, 1--large operator, 2--binary operation, +3--relational operation, 4--math delimiter, 5--right delimiter, +6--punctuation mark, and 7--adjustable. +We use classes 7, 8, 9 as extra free ones. + + + + +\Section{Scanning Requests} + +\`'{\everypar{}\special{t4ht^i}$sym... i=0, 1, 2, 3, 4,..., a, b, ...., ~ +$\special{t4ht^}}' + + +A right delimiter immediately after a math openimiter ammuses +a matching pair. + +\List{*} +\item \`'\special{t4ht^i}' - on class i-'0' (i='0', '1', ..., \`'~' +\item \`'\special{t4ht^-}'--pause from processing delimiters +\item \`'\special{t4ht^+}'--continue processing delimiters +\item + \`'\special{t4ht^}'--off, if in scan-mode of class values. +on/off show-class, otherwise +\item +\`'\special{t4ht^i*...*...}'---Configure delimiters for class i +\item \`'\special{t4ht^ix}'--put delimiters of class i on next group. +If x=\`'>' ignore delimiters within the group. +\item \`'\special{t4ht^i)*...*...}'--put the specified delimiters of + class on next group, instead of the default ones. +Ignore delimiters within the group. +\item \`'\special{t4ht^i(*...*...}'--put the specified delimiters of + class on next group, instead of the default ones. +Don't ignore delimiters within the group. +\EndList + + + + + + + +\<classes for math symbols\><<< +switch( special_n ){ + case 0:{ if( math_class_on ){ + open_del = 256; pause_class = ignore_subclass_del = 0; + math_class_on = FALSE; `<recall intrusive flags`> + } else { show_class = !show_class; } + break; + } + case 1:{ `<save intrusive flags`> + special_n--; + if( (math_class = scan_class(1)) == `<num of math classes: 79`> ) + { math_class = 0; } + else math_class_on = TRUE; + break; + } + case 2:{ `<class delimiters on group`> + break; } + default:{ `<set config class dels`> } +} +>>> + + + + + +\<vars\><<< +static BOOL math_class_on = FALSE, show_class = FALSE; +static int open_del = 256, math_class, pause_class, ignore_subclass_del; +>>> + +\`'open_del' is used by close delimiter, if they are immediate +neighbors. + +\<vars\><<< +static int sv_group_dvi, sv_trace_dvi_C, sv_in_trace_char, sv_span_on, + sv_in_span_ch; +>>> + +\<save intrusive flags\><<< +sv_group_dvi = group_dvi; +sv_trace_dvi_C = trace_dvi_C; +sv_in_trace_char = in_trace_char; +sv_span_on = span_on; +sv_in_span_ch = in_span_ch; +>>> + + +\<recall intrusive flags\><<< +group_dvi = sv_group_dvi; +trace_dvi_C = sv_trace_dvi_C; +in_trace_char = sv_in_trace_char; +span_on = sv_span_on; +in_span_ch = sv_in_span_ch; +>>> + + + + + + + +\<header functions\><<< +static int scan_class( ARG_I(int) ); +>>> + +\<functions\><<< +`[ +static int scan_class( flag ) + int flag +;{ int math_class; + math_class = get_char(); + if( (math_class >= '0' ) + && (math_class < '0' + `<num of math classes: 79`>) ){ + { math_class -= '0'; } + } else { + if( flag== 1 ) { + switch( math_class ){ + case '-': { math_class = `<num of math classes: 79`>; + pause_class++; break; } + case '+': { math_class = `<num of math classes: 79`>; + pause_class--; break; } + default: { math_class = 0; } + } } else if( flag== 2 ) { + switch( math_class ){ + case `<ignore sub dels ch`>: { + math_class = `<ignore sub dels val`>; break; } + case `<end ignore sub dels ch`>: + { math_class = `<end ignore sub dels val`>; break; } + default: { math_class = 0; } + } + } else { math_class = 0; } + } + return math_class; +} +>>> + + + +\Section{Setting Requests} + + +\<header functions\><<< +static INTEGER set_ch_class( ARG_I(int) ); +>>> + +\<functions\><<< +`[ +static INTEGER set_ch_class(ch) int ch +;{ int r_ch; + r_ch = ch - font_tbl[cur_fnt].char_f; + if( math_class == `<math close`> ){ + store_bit_I( font_tbl[cur_fnt].math_closing, r_ch ); + *(font_tbl[cur_fnt].math + r_ch) = + (char) ((open_del == 256)? ch : open_del); + } else { + store_bit_Z( font_tbl[cur_fnt].math_closing, r_ch ); + *(font_tbl[cur_fnt].math + r_ch) = math_class; + } + open_del = ( math_class == `<math open`> )? ch : 256; + `<return char width`> +} +>>> + +\<set-ch-class(ch-1)\><<< +set_ch_class(ch_1) +>>> + + + +\<set config class dels\><<< +{ U_CHAR str[256], *p, ch, **q; + math_class = scan_class(2); ch = get_char(); + special_n -= 2; p = str; + while( special_n-- > 0 ){ + if( (*(p++) = get_char()) == ch ){ p--; break; } + } + *p = '\0'; + q = (math_class > `<math classes 0..78`>)? &(`<push class del := ...`>) + : &(open_class[math_class]); + *q = (char *) r_alloc((void *) open_class[math_class], + 1 + (size_t) strlen((char *) str)); + (IGNORED) strcpy((char *) *q, (char *) str); + q = (math_class > `<math classes 0..78`>) ? &(`<pop class del := ...`>) + : &(close_class[math_class]); + p = *q = (char *) r_alloc((void *) *q, 1 + (size_t) special_n); + while( special_n-- > 0 ){ *(p++) = get_char(); } + *p = '\0'; + if( math_class > `<math classes 0..78`>){ `<next delimiters on group`> } +} +>>> + + +When \`'math_class > max math class' is true, the delimiters are +placed on the next group. In such a case a math class of \`')' also +requests that no subdelimiter will be placed there. + +\<header functions\><<< +static int math_class_of( ARG_II(int,int) ); +>>> + +\<functions\><<< +`[ +static int math_class_of(ch,cur_fnt) int ch`; int cur_fnt +;{ int math_class; + math_class = ch - font_tbl[cur_fnt].char_f; + return ((get_bit( font_tbl[cur_fnt].math_closing, math_class))? + `<math close`> : *( math_class + font_tbl[cur_fnt].math)); + +} +>>> + + + + +\Section{Memory and Initialization} + + + + +\<vars\><<< +static U_CHAR *open_class[`<mems for math classes (79 + 2 )`>], + *close_class[`<mems for math classes (79 + 2 )`>]; +>>> + +There are 79 characters in the range between the digit `0' and +the character \`'~'. + +\<math classes 0..78\><<< +78 +>>> + +\<num of math classes: 79\><<< +79 +>>> + + +The following should be characters below the digit `0' + +\<ignore sub dels ch\><<< +')' +>>> + +\<end ignore sub dels ch\><<< +'(' +>>> + +\<ignore sub dels val\><<< +(`<num of math classes: 79`> + 1) +>>> + +\<end ignore sub dels val\><<< +(`<num of math classes: 79`> + 2) +>>> + + +\<mems for math classes (79 + 2 )\><<< +82 `%one extra is needed?`% +>>> + + + + + + + +\<main's init\><<< +for( math_class=0; math_class<`<num of math classes: 79`>; math_class++ ){ + open_class[math_class] = m_alloc(char, 1); + close_class[math_class] = m_alloc(char, 1); + *(open_class[math_class]) = *(close_class[math_class]) = '\0'; +} +>>> + + + + +\<entries for math classes\><<< +char *math, *math_closing; +>>> + +\<memory for math classes\><<< +new_font.math_closing = m_alloc(char, n_gif_bytes ); +new_font.math = m_alloc(char, n_gif ); +>>> + + +\<init math-closing\><<< +new_font.math_closing[i] = +>>> + +\<init math\><<< +new_font.math[i] = +>>> + +\<merge math entries\><<< +free((void *) new_font.math_closing ); + new_font.math_closing = font_tbl[ k ].math_closing; +free((void *) new_font.math ); + new_font.math = font_tbl[ k ].math; +>>> + + + + + +\Section{Delimiters Over Next Group} + +\SubSection{Requests} + + \`'\special{t4ht^ix}'--put delimiters of class i on next group/token. If +{\tt x=`)'} ignore delimiters within the group. + + +\<class delimiters on group\><<< +special_n -= 2; math_class = scan_class(0); +stack[stack_n+1].ignore_subclass_del = + (`<ignore sub dels ch`> == get_char()); +stack[stack_n+1].active_class_del = TRUE; +stack[stack_n+1].temp_class_del = FALSE; +stack[stack_n+1].no_left_del = TRUE; +stack[stack_n+1].class_open = open_class[math_class]; +stack[stack_n+1].class_close = close_class[math_class]; +>>> + + + \`'\special{t4ht^)x*...*...}'--put the specified delimiters of + class on next group, instead of the default ones. +If {\tt x=`)'}, ignore delimiters within the group. + + + + +\<next delimiters on group\><<< +stack[stack_n+1].ignore_subclass_del = + (math_class == `<ignore sub dels val`>); +stack[stack_n+1].temp_class_del = TRUE; +stack[stack_n+1].active_class_del = TRUE; +>>> + + + +\<pop class del := ...\><<< +stack[stack_n+1].temp_class_close +>>> + +\<push class del := ...\><<< +stack[stack_n+1].temp_class_open +>>> + + + + +\SubSection{Insertions} + +\<add push class del\><<< +if( stack[stack_n].active_class_del ){ + if( show_class && !pause_class && !ignore_subclass_del ){ + `<print open del of group class`> + } + ignore_subclass_del = ignore_subclass_del + + stack[stack_n].ignore_subclass_del; + stack[stack_n+1].no_left_del= FALSE; +} +>>> + + +\<add pop class del\><<< +if( stack[stack_n].active_class_del ){ + ignore_subclass_del = ignore_subclass_del + - stack[stack_n].ignore_subclass_del; + if( show_class && !pause_class && !ignore_subclass_del ){ + `<print right del of group class`> + } + stack[stack_n].active_class_del = FALSE; +} +>>> + + + +\SubSection{Memory and Initialization} + + + + +\<struct stack_entry\><<< +char *class_open, *class_close, + *temp_class_open, *temp_class_close; +BOOL temp_class_del, ignore_subclass_del, active_class_del, + no_left_del, sv_no_left_del; +>>> + +The math class can be on a group or a token. Upon reaching the +\''\special', the \''no_left_del' is set to false. Upon reaching to +the start of the next group (not token), the flag is set to true. + + + + + +\<initialized entries for grouping stack\><<< +stack[i].class_open = stack[i].class_close + = (char *) 0; +stack[i].temp_class_open = m_alloc(char, 1 ); +stack[i].temp_class_close = m_alloc(char, 1 ); +stack[i].ignore_subclass_del = stack[i].temp_class_del + = stack[i].active_class_del + = FALSE; +>>> + + +\Section{Delimiters Over Next Character} + + + +\<left class delNO\><<< +if( show_class && !pause_class && !ignore_subclass_del){ + if(stack[stack_n+1].no_left_del && stack[stack_n+1].active_class_del ){ + `<open del of group class on ch`> + } else { + math_class = math_class_of( ch, cur_fnt ); + (IGNORED) print_f( open_class[math_class]); +} } +>>> + + +\<left class del\><<< +if( show_class && !pause_class && !ignore_subclass_del){ + if( !stack[stack_n].no_left_del && stack[stack_n+1].active_class_del ){ + `<open del of group class on ch`> + if( !stack[stack_n+1].ignore_subclass_del ){ + `<left del of class on ch`> + } + } else { + `<left del of class on ch`> +} } +>>> + + +\<left del of class on ch\><<< +math_class = math_class_of( ch, cur_fnt ); +(IGNORED) print_f( open_class[math_class]); +>>> + + +The \`'stack[stack_n].no_left_del' is true if we have a request for +math delimiters on next group/token, and no left delimiter had +been placed on a group. + +\<right class delNO\><<< +if( show_class && !pause_class && !ignore_subclass_del ){ + if(stack[stack_n+1].no_left_del && stack[stack_n+1].active_class_del ){ + `<right del of group class on ch`> + stack[stack_n+1].active_class_del = FALSE; + } else { + (IGNORED) print_f( close_class[math_class]); + } +} +>>> + +\<right class del\><<< +if( show_class && !pause_class && !ignore_subclass_del ){ + if( !stack[stack_n].no_left_del && stack[stack_n+1].active_class_del ){ + if( !stack[stack_n+1].ignore_subclass_del ){ + `<right del of class on ch`> + } + `<right del of group class on ch`> + stack[stack_n+1].active_class_del = FALSE; + } else { + `<right del of class on ch`> + stack[stack_n+1].active_class_del = FALSE; `%%%%%%%%NEW%%%%`% + } +} +>>> + +\<right del of class on ch\><<< +(IGNORED) print_f( close_class[math_class]); +>>> + + + + +\<print right del of group class\><<< +(IGNORED) print_f( (stack[stack_n].temp_class_del)? + stack[stack_n].temp_class_close + : stack[stack_n].class_close); +>>> + +\<right del of group class on ch\><<< +(IGNORED) print_f( (stack[stack_n+1].temp_class_del)? + stack[stack_n+1].temp_class_close + : stack[stack_n+1].class_close); +>>> + + +\<print open del of group class\><<< +(IGNORED) print_f( (stack[stack_n].temp_class_del)? + stack[stack_n].temp_class_open + : stack[stack_n].class_open); +>>> + +\<open del of group class on ch\><<< +(IGNORED) print_f( (stack[stack_n+1].temp_class_del)? + stack[stack_n+1].temp_class_open + : stack[stack_n+1].class_open); +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Chapter{Files and Directories} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Environment File (tex4ht.env)} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\List{1} +\item Try the file given by the -e switch of tex4ht command. +\item Search the current directory for one (i.e., open "tex4ht.env"). +\item Search the program's directory (dos/w32) +\item Home directory (\`'~` unix; \`'C:' dos/w32) +\item Compiled directory within ENVFILE +\EndList + + +First character is a flag character to be consistent with command line +options. Undefined flags signal comment lines. + + + + + +Search along the path: command line file $\rightarrow$ work +directory $\rightarrow$ home directory $\rightarrow$ system file. + +\<get .env directory from com ln\><<< +tex4ht_env_file = p+2; +>>> + + +% if( !access(p+2,F_OK) ) tex4ht_env_file = p+2; +% else warn_i_str(12,p+2); + + +\<main's vars\><<< +char* tex4ht_env_file = (char *) 0; +char* dos_env_file = +#if defined(__MSDOS__) + `<get dos env file`>; +#endif +#if !defined(__MSDOS__) + (char *) 0; +#endif + +>>> + + +In dos we can't have file names consisted only of the extension +\`'.tex4ht', let alone the length of the extension. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{General} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + +\<vars\><<< +static BOOL dump_env_search = FALSE; +>>> + +\<trace env search\><<< +dump_env_search = TRUE; +>>> + +\<find tex4ht.env\><<< +{ U_CHAR str[PATH_MAX], *TEX4HTENV; + `<env file from command switch`> + `<env file at work dir`> + if( !dot_file ){ + `<TEX4HTENV env`> + } + `<env file at root dir`> + `<ENVFILE env`> + `<env from prog dir`> + `<kpathsea env file`> + if( !dot_file ) { bad_in_file(`<warn 1`>); } /* give up if no tex4ht.env */ +} +>>> + + + + +\<env file from command switch\><<< +if( dump_env_search && tex4ht_env_file ){ + (IGNORED) printf("-e: %s?\n", tex4ht_env_file); +} +dot_file = tex4ht_env_file? + f_open_pathed_filename( tex4ht_env_file, READ_TEXT_FLAGS ) : NULL; +>>> + + + + + +\<env file at root dir\><<< +if( !dot_file ){ + if( HOME_DIR ){ + (IGNORED) sprintf(str,`<"s/tex4ht.env"`>, HOME_DIR); + if( dump_env_search ){ (IGNORED) printf("%s?\n", str); } + dot_file = f_open(str,READ_TEXT_FLAGS); +} } +#ifndef DOS_WIN32 + if( !dot_file ){ + if( HOME_DIR ){ + (IGNORED) sprintf(str,"%s/.tex4ht", HOME_DIR); + if( dump_env_search ){ (IGNORED) printf("%s?\n", str); } + dot_file = f_open(str,READ_TEXT_FLAGS); + } } +#endif +#if defined(__MSDOS__) + if( !dot_file ){ + if( dump_env_search ){ (IGNORED) printf("%s?\n", "C:/tex4ht.env"); } + dot_file = f_open("C:/tex4ht.env",READ_TEXT_FLAGS); + } +#endif +>>> + + + + +\<env from prog dir\><<< +if( !dot_file && dos_env_file){ + if( dump_env_search ){ (IGNORED) printf("%s?\n", dos_env_file); } + dot_file = f_open( dos_env_file, READ_TEXT_FLAGS ); +} +>>> + +\<env file at work dir\><<< +if( !dot_file ){ + if( dump_env_search ){ (IGNORED) printf("%s?\n", "tex4ht.env"); } + dot_file = f_open("tex4ht.env", READ_TEXT_FLAGS); +} +#ifndef DOS_WIN32 + if( !dot_file ){ + if( dump_env_search ){ (IGNORED) printf("%s?\n", ".tex4ht"); } + dot_file = f_open(".tex4ht", READ_TEXT_FLAGS); + if( dot_file ){ + printf("(%s)\n", ".tex4ht"); + } } +#endif +>>> + + +\<ENVFILE env\><<< +#ifdef ENVFILE + if( !dot_file ){ + if( dump_env_search ){ (IGNORED) printf("ENVFILE: %s?\n", ENVFILE); } + dot_file = f_open_pathed_filename( ENVFILE,READ_TEXT_FLAGS); + } +#else + if( dump_env_search ){ + (IGNORED) printf("tex4ht compiled without ENVFILE\n"); + } +#endif +>>> + +\<TEX4HTENV env\><<< +TEX4HTENV = getenv("TEX4HTENV"); +if( TEX4HTENV ){ + if( dump_env_search ){ + (IGNORED) printf("TEX4HTENV: %s?\n", TEX4HTENV); } + dot_file = f_open_pathed_filename(TEX4HTENV,READ_TEXT_FLAGS); +} else { + if( dump_env_search ){ + (IGNORED) printf("getenv(\"TEX4HTENV\")=\n"); +} } +>>> + +\<h-defines\><<< +#ifndef ENVFILE + +#endif +>>> + + +\<"s/tex4ht.env"\><<< +#if defined(__DJGPP__) + is_forward_slash(HOME_DIR)? "%s/tex4ht.env" : "%s\\tex4ht.env" +#else + "%s/tex4ht.env" +#endif +>>> + + + +\<warn 1\><<< +#ifdef DOS_WIN32 + "tex4ht.env" +#else + "tex4ht.env | .tex4ht" +#endif +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{For Dos} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + One last remark about the source: I have implemented a routine that +changes the functionality of searching for tex4ht.env a bit. DOS +organises programs differently than Unix; it is convention to place the +program and all related files, including configuration files, in a +dedicated directory. In addition, DOS (being single-user) doesn't have +home directories. Knowing this, the best way to find the tex4ht.env file +is: + +\List{1} +\item Search the current directory for one (i.e., open "tex4ht.env"). +\item Search the program's directory +\item Give up (no point in checking the root directory). +\EndList + + Under DOS, argv[0] usually includes the full path to the program - +even if it wasn't typed in. This can be used to find the program's own +directory, and hence the configuration file. I've implemented this +already as follows: + +\<get dos env file\><<< +get_env_dir(argv[0]) +>>> + +\<functions\><<< +#if defined(__MSDOS__) +`<get tex4ht.env in dos`> +#endif +>>> + + + + +\<get tex4ht.env in dos\><<< +`[ +static char *get_env_dir(progname) + U_CHAR *progname + +;{ int i; + U_CHAR *p; + if(! progname || ! *progname) return NULL; `% Safety `% + i = (int) strlen((char *) progname); + while( (progname[--i] != (int) dir_path_slash(progname) ) + && (i > 0) ) ; `%Search for dir`% + if(i == 0) return NULL; `%Not found? Give up`% + p = (char *) malloc(i+12); + if(p == NULL) return NULL; `%Space for new extention after dot`% + strncpy(p, progname, i+1); `%Copy up to slash`% + (IGNORED) strcpy((char *) &p[i+1], "tex4ht.env"); `%Append new extention`% + return p; +} +>>> + +The 12 above is for accomodating \''tex4ht.env'. + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Get Script} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +Options + +\List{} +\item{s} +Block of lines +starting with the same +character: s (set +format of +script commands), e.g., \`'s--- needs --- %%1.idv[%%2] ==> %%3 ---' +\item{b} Begin-of-characters/end-of-figures comment, e.g., \`'b--- characters ---' +\item{g} Gif extension, e.g., \`'g.gif' +\item{a} Font alias, e.g., \`'acmtex cmtt' +\item{t} Directory of tfm fonts, e.g., \`'t/n/candy/0/tex/teTeX/texmf/fonts/tfm/!' +\item{i} Directory of htf fonts, e.g., \`'i/n/gold/5/gurari/tex4ht.dir/ + i/n/gold/5/gurari/tex4ht.dir/ht-fonts/iso88591/!'. +\EndList + + +Priority (the easier to change, the higher in priority). + +\List{disk} +\item Command line +\item Environment File +\item Hard coded in program +\EndList + +\<header functions\><<< +static char* get_script( ARG_III(char *, const U_CHAR *, int) ); +>>> + +\<functions\><<< +`[ +static char* get_script(name, inln,x) + char * name`; + const U_CHAR * inln`; + int x + +;{ + if( !name ) + { U_CHAR str[256], *ch; + (IGNORED) fseek(dot_file, 0L, `<abs file addr`>); + if( search_dot_file( x ) ){ + `<read x-script from dot file`> + } else {(IGNORED) strcpy((char *) str, inln); } + ch = m_alloc(char, (int) strlen((char *) str)+2); + (IGNORED) strcpy((char *) ch, (char *) str); + return ch; + }else return name; +} +>>> + +We allocate extra character for possible addition of \`'%' +at end of string. + +\<read x-script from dot file\><<< +ch = str; str[254] = '\0'; +do{ int int_ch; + while((*(ch++) = (char) + (int_ch = (int) getc(dot_file)) + ) != '\n'){ + if( int_ch == EOF ){ *(ch-1)='\n'; break; } + if( str[254] ){ warn_i_int(33, x); break; } + } +}while( (int) getc(dot_file) == x ); +*ch = '\0'; +>>> + +The \`'if( *(ch-1) == EOF ){...}' +is for the case that the last line not terminates with a return. + +%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Search Env File} +%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\<header functions\><<< +static BOOL search_dot_file( ARG_I( int) ); +>>> + +\<functions\><<< +`[ +static BOOL search_dot_file( ch ) + int ch +;{ int chr; + + while( TRUE ){ + chr = getc(dot_file); + if( chr == ch ){ return TRUE; } + if( chr == '<' ) { + `<skip non -c env segments`> + continue; + } + if( chr == '\n' ){ continue; } + do + if( chr == EOF ) return FALSE; + while( (chr = getc(dot_file)) != '\n' ); +} } +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% *p, + +\<skip non -c env segments\><<< + U_CHAR match[256]; + int i; +for( i = 0; (chr != '\n') && (chr != EOF ) ; i++){ + chr = (int) getc(dot_file); + match[i] = (U_CHAR) chr; +} +match[i-1] = '\0'; +if( match[0] != '/' ){ + BOOL env_skip; + for( i = 0; + (match[i] != '>') && (match[i] != '\n') && (match[i] != EOF ); + i++){} + if( match[i] == '>' ){ match[i] = '\0'; } + `<env-skip = skip segment match[1]`> + if( env_skip ){ + `<skip env segment`> +} } +>>> + +\<skip env segment\><<< + U_CHAR cur_block[90]; + BOOL status; +(IGNORED) strcpy((char *) cur_block, (char *) match); +status = FALSE; +while( !status && (chr != EOF) ){ + chr = 'x'; + for( i = 0; (chr != '\n') && (chr != EOF ) ; i++){ + chr = (int) getc(dot_file); + match[i] = (U_CHAR) chr; + } + match[i-1] = '\0'; + for(i=0; match[i]!='\0'; i++){ + if( match[i] == '>' ){ break; } + } + if( (match[0] == '<') && (match[1] == '/') + && (match[i] == '>') ){ + match[i]='\0'; + status = eq_str(match+2, cur_block); + } else { status = FALSE; } +} +>>> + + + + + +\<defines\><<< +struct env_c_rec{ + char *option; + struct env_c_rec *next; +}; +>>> + +\<vars\><<< +static struct env_c_rec *envChoice + = (struct env_c_rec*) 0; +>>> + + +\<env blocks selector\><<< +struct env_c_rec *temp = (struct env_c_rec*) + m_alloc(struct env_c_rec, (int) 1); +temp->option = p+2; +temp->next = envChoice; +envChoice = temp; +>>> + +\<env-skip = skip segment match[1]\><<< +if( envChoice == (struct env_c_rec*) 0 ){ + env_skip = !eq_str(match, "default" ); +} else { + struct env_c_rec *p; + env_skip = TRUE; + for( p=envChoice; p!=(struct env_c_rec*) 0 ; p = p->next ){ + if( eq_str(match, p->option ) ){ env_skip = FALSE; } +} } +>>> + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Locating the TFM Fonts} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +Flag `t' identifies font directories. +Command line (can be multiple) $\rightarrow$ work directory +$\rightarrow$ dot file $\rightarrow$ system directory. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Command Line Options} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\List{*} +\item Specifying multiple directories is possible; paths are separated + with ':' under Unix, ';' under DOS. (This isn't really important + perhaps, but it seems a nice feature). + +Instead of concatenated directories we allow multiple ones. + +\item If a path specification ends in a '!', it's subdirectories are + searched too, else only the specified dir is searched. (This is the + way many TeX installations seem to do it, too). +\EndList + + + +\<get tfm font dir from com ln\><<< +com_dir(p); fontdir[fontdir_count++] = p+2; +>>> + +The \`'access' function returns 0 if the path is fine; -1 for error. + + + +\<vars\><<< +static U_CHAR *fontdir[MAXFDIRS]; +static int fontdir_count = 0; +>>> + +What the use of the following? Do we wants to make it h-defines. + +\<defines\><<< +#ifndef MAXFDIRS +#define MAXFDIRS 100 +#endif +>>> + + Also, check how many directories and fonts are +used. \`'tex4ht.log' claims 55 fonts with 255 as limit. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{The Search} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\'' struct cache_font_rec *cur_cache_font; '? + +\<search dirs for font\><<< +{ `% int i; `% + font_file = NULL; + (IGNORED) sprintf(file_name, "%s.tfm", new_font_name); + `<if kpathsea tfm files else`> + `<search font in cache dirs`> + if( !font_file ){ int i; + for( i = fontdir_count; i--; ){ + if( (font_file = search_file_base(file_name, fontdir[i], + READ_BIN_FLAGS, tfm_dirs)) + != NULL ) break; } + } + if( !font_file ) font_file = f_open(file_name, READ_BIN_FLAGS); + if( !font_file && dot_file ) + font_file = search_in_dot_file( 't', file_name, + READ_BIN_FLAGS, tfm_dirs); + `<search TFMDIR`> + `<endif kpathsea tfm files`> +} +>>> + + + + + +KPATHSEA has a database LS-R which corresponds to a \`'ls -R *' +listing of files and the directories including them. This allow for a +quick search of files within the image of the directory stored within +the database, instead of live search in the directories themselve which +consume disk access time. + + +\<search TFMDIR\><<< +#ifdef TFMDIR + if( !font_file ) + font_file = search_file_base(file_name, TFMDIR, + READ_BIN_FLAGS, tfm_dirs); +#endif +>>> + +\<h-defines\><<< +#ifndef TFMDIR + +#endif +>>> + + + +\SubSection{Get Font Env Variables} + + +The environment variables, if defined, hold a sequence of directory +names. Each directory name can be an absolute address, or relative to +the home directory (signaled by the prefix \`'~'). The directories must be separated by a distinguished character, which must also act as delimiter at the start and the end of the string. + + +\<check env font variables\><<< +#ifndef KPATHSEA +tfm_dirs = get_env_var("TEX4HTTFM"); +#endif +htf_dirs = get_env_var("TEX4HTHTF"); +>>> + + + + + + +\<header functions\><<< +static struct env_var_rec * get_env_var( ARG_I(const char *) ); +>>> + +\<functions\><<< +`[ +static struct env_var_rec * get_env_var( env_var ) + const char *env_var +;{ U_CHAR *TEX4HTTFM, *from; + struct env_var_rec *tfm_dirs, *p; + int env_var_len; + tfm_dirs = (struct env_var_rec *) 0; + TEX4HTTFM = getenv( env_var ); + if( TEX4HTTFM ){ + env_var_len = (int) strlen((char *) TEX4HTTFM); + if ( *TEX4HTTFM == *(TEX4HTTFM + env_var_len - 1 ) ){ + from = TEX4HTTFM + env_var_len - 1; + *from = '\0'; + do{ + from--; + if( *from == *TEX4HTTFM ){ char * base; + *from = '\0'; + base = from + 1; + `<verify env var dir`> + if( base ){ + `<add env var dir`> + } } + } while (from > TEX4HTTFM ); + } else { warn_i_str2( 49, env_var, TEX4HTTFM); } + } + return tfm_dirs; +} +>>> + +We preseve the order of the directories founnd in the environment +variables. + + +\<add env var dir\><<< +p = m_alloc(struct env_var_rec, 1); +p->next = tfm_dirs; +p->base = base; +tfm_dirs = p; +>>> + + +\<verify env var dir\><<< +{ U_CHAR *str; + if( *(from+1) == '~' ){ + if( HOME_DIR ){ + str = m_alloc(char, strlen((char *) HOME_DIR)+strlen((char *) base)); + (IGNORED) sprintf(str,"%s%s", HOME_DIR, base+1); + if( access(str,F_OK) ) { + warn_i_str2(49, env_var, str); base = NULL; } + free((void *) str); + } else { + if( access(base,F_OK) ) { + warn_i_str2(49, env_var, base); base = NULL; } + } + } else { + if( access(base,F_OK) ) { + warn_i_str2(49, env_var, base); base = NULL; } +} } +>>> + + + + +\<scan fonts vars\><<< +#ifndef KPATHSEA +struct env_var_rec *tfm_dirs; +#endif +struct env_var_rec *htf_dirs; +>>> + +\<types\><<< +struct env_var_rec{ char* base; + struct env_var_rec *next; }; +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Cache Directories} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + +\<search font in cache dirs\><<< +for( cur_cache_font = cache_font; + cur_cache_font; + cur_cache_font = cur_cache_font->next ) + if( (font_file = search_file(file_name, + cur_cache_font->dir, + READ_BIN_FLAGS)) + != NULL) break; +>>> + + + + +\<put dir in cache\><<< +{ int found; + found = FALSE; + for( cur_cache_font = cache_font; + cur_cache_font; + cur_cache_font = cur_cache_font->next ) + { found = found || eq_str(cur_cache_font->dir, dir ) ; + if( found ) break; } + if( !found ){ + cur_cache_font = m_alloc(struct cache_font_rec, 1); + `<init new cache list`> + cur_cache_font->dir = m_alloc(char, n+1); + (IGNORED) strcpy((char *) cur_cache_font->dir, dir); + if( !cache_font ){ + cur_cache_font->next = cache_font; + cache_font = cur_cache_font; + } else if ( gt_str(cache_font->dir, dir) ) { + cur_cache_font->next = cache_font; + cache_font = cur_cache_font; + } else { + struct cache_font_rec * after_cache_font; + after_cache_font = cache_font; + while( after_cache_font->next ){ + if ( gt_str(after_cache_font->next->dir, dir) ) { break; } + after_cache_font = after_cache_font->next; + } + cur_cache_font->next = after_cache_font->next; + after_cache_font->next = cur_cache_font; +} } } +>>> + + + + + +\<free html font memory\><<< +while( (cur_cache_font = cache_font) != (struct cache_font_rec *)0 ){ + cache_font = cache_font->next; + free((void *) cur_cache_font->dir ); + free((void *) cur_cache_font ); } +>>> + + +\<vars\><<< +static struct cache_font_rec *cache_font, *cur_cache_font; +>>> + +\<init scan fonts vars\><<< +cache_font = (struct cache_font_rec *) 0; +cur_cache_font = (struct cache_font_rec *) 0; +>>> + +\<types\><<< +struct cache_font_rec{ char* dir; + struct cache_file_rec * cache_file; + struct cache_font_rec* next; }; +struct cache_file_rec{ struct cache_file_rec* next; + U_CHAR * file; }; +>>> + + + +\SubSection{Default Built-In During Compilation} + + On my HP the standard +TeX fonts are in the directory +%\Link[/usr/local/tex/lib/texmf/fonts/public/cm/tfm/]{}% +\Link[/usr/local/tex/lib/texmf/fonts/public/cm/tfm/]{}{}% + /usr/local/tex/lib/texmf/fonts/public/cm/tfm/\EndLink, +and the standard latex fonts are in +\Link[/usr/local/tex/lib/texmf/fonts/public/latex/tfm/]{}{}% + /usr/local/tex/lib/texmf/fonts/public/latex/tfm/\EndLink, +on my SUN the directory is ???. + + +We also might want to put the current directory in. + + + + +The function \`'int access(const U_CHAR *pathname, int mode)', and the mode +\`'F_OK' that tests for the existence of file, are defined in the +following directory. The function returns 0 if ok and -1 on error . + +Where access comes from in dos? in \''<io.h>' + +\<h-include\><<< +#ifndef F_OK +#ifdef DOS_WIN32 +#define F_OK 0 `% does file exist `% +#endif +#ifndef KPATHSEA +#ifndef DOS_WIN32 +#define HAVE_UNISTD_H +#endif +#endif +#endif +#ifdef HAVE_IO_H +#include <io.h> +#endif +#ifndef KPATHSEA +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#endif +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Htf Font Files} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Search along the path: +command line switch 'i' directory $\rightarrow$ +work directory $\rightarrow$ directories specified in tex4ht.env +(switch 'i' and aliased 'a') $\rightarrow$ system directory +specified in HTFDIR. \ifHtml[\HPage{more}\Verbatim + + > This I think leads to a problem in the parsing of ht-font + > information (the ``a'' lines in the .env file): according to your rules, only + > the first setting takes effect. So of t4ht has previsouly fou nd and read + ^^^^ + tex4ht + > a tex4ht.env file, then the upshot is that the user's ``a'' section doesn't + > override the default. At least this is what I think must be happening + > based on some experiments I'm doing with a custom .env file. + +The search for the htf files should be along the following route + + in the directories stated within `-i' switches of the tex4ht command line + in the work directory + in the directories specified within `i' records of the env file + in a directory compiled into tex4ht during its compilation + +The search for the env file should be along the following route + + in the file stated within the `-e' switch of the tex4ht command line + in the work directory + in the home directory (~-unix; C:-dos/win) + in a directory compiled into tex4ht during its compilation +\EndVerbatim\EndHPage{}]\fi + + + + + + +\<file = .htf file\><<< +{ U_CHAR name[256]; + (IGNORED) sprintf(name, "%s.htf", new_font_name); + `<search file in htf locations`> + if( file ){ `<check name decomposition`> } +} +>>> + + +\<search file in htf locations\><<< + file = NULL; + `<search htf font along cmd switches`> + if( !file ){ + if( ((file = f_open(name, READ_TEXT_FLAGS)) == NULL) && dot_file ) + file = search_in_dot_file( 'i', name, READ_TEXT_FLAGS, htf_dirs); +#ifdef HTFDIR + if( !file ) file = search_file_base(name, HTFDIR, + READ_TEXT_FLAGS, htf_dirs); +#endif + `<file = kpathsea .htf file`> + } +>>> + + + + +\<types\><<< +struct htf_com_rec{ char* name; + struct htf_com_rec* next; }; +>>> + +\<main's vars\><<< +struct htf_com_rec* htf_font_dir = (struct htf_com_rec *) 0; +>>> + +\<get htf font dir from com ln\><<< + com_dir(p); + { + struct htf_com_rec *q, *t; + q = m_alloc( struct htf_com_rec, 1); + q->name = p+2; + q->next = (struct htf_com_rec *) 0; + if( htf_font_dir ){ + t = htf_font_dir; + while( t->next ){ t = t->next; } + t->next = q; + } else { + htf_font_dir = q; + } +} +>>> + + + + +\<header functions\><<< +static void com_dir( ARG_I(char*) ); +>>> + +\<functions\><<< +`[ +static void com_dir(p) + char* p +;{ int i; U_CHAR str[256]; + (IGNORED) strcpy((char *) str, (char *) p+2 ); + i = (int) strlen((char *) str) - 1; + if( str[i] == '!' ) str[i] = '\0'; +} +>>> + +% if( !access(str,F_OK) ) return TRUE; +% warn_i_str(12,p+2); return FALSE; + + + + + +\<search htf font along cmd switches\><<< +{ + struct htf_com_rec *p; + p = htf_font_dir; + while( p ){ + file = search_file_base(name, p->name, READ_TEXT_FLAGS, htf_dirs); + if( file ){ +#ifndef KPATHSEA + tex4ht_fls = TRUE; +#endif + break; + } + p = p->next; + } +} +>>> + + + +\<h-defines\><<< +#ifndef HTFDIR + +#endif +>>> + +Example \`' #define HTFDIR "/n/gold/5/gurari/tex4ht-fonts.dir/"' + + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{External File Cache} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + +\<init new cache list\><<< +cur_cache_font->cache_file = (struct cache_file_rec *) 0; +>>> + +\<store filename in cache\><<< +{ + struct cache_file_rec *file_rec, *prev_file_rec; + prev_file_rec = (struct cache_file_rec *) 0; + file_rec = cur_cache_font->cache_file; + while( file_rec ) { + if( !gt_str(name,file_rec->file) ) break; + prev_file_rec = file_rec; + file_rec = file_rec->next; + } + { + struct cache_file_rec * file_entry; + BOOL flag; + flag = TRUE; + if( file_rec ) { + if( eq_str(name,file_rec->file) ){ flag = FALSE; } + } + if( flag ) { + `<insert file name`> + } + } +} +>>> + + +\<insert file name\><<< +file_entry = m_alloc(struct cache_file_rec, 1); +file_entry->file = m_alloc(char, strlen(name)+1); +(IGNORED) strcpy((char *) file_entry->file, name); +if( ! cur_cache_font->cache_file ){ + cur_cache_font->cache_file = file_entry; + file_entry->next = (struct cache_file_rec *) 0; +} else if( !prev_file_rec ){ + file_entry->next = cur_cache_font->cache_file; + cur_cache_font->cache_file = file_entry; +} else { + file_entry->next = prev_file_rec->next; + prev_file_rec->next = file_entry; +} +>>> + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Search File in Aux Cache from dot directories} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +The cache file holds directory names and file names. Directory names +are preceded by a space, and file names start at column one. + +\Verbatim + /usr/local/share/texmf/tex4ht/ht-fonts/iso8859/1/ae +ae.htf +aecsc.htf + /usr/local/share/texmf/tex4ht/ht-fonts/iso8859/1/cm +cmcsc.htf +cmr.htf + /usr/local/share/texmf/tex4ht/ht-fonts/unicode/cm +cmmi.htf +\EndVerbatim + + +We traverse the auxiliary cache file, recording on the way the last +found directory. Upon finding a match on file name, we check the last +recorded directory against the directories mentioned in the +environment file. If a match is found also there, we +open the appropriate file. + + +\<search font in cache files\><<< + U_CHAR cache_dir[256], dot_dir[256], *p, *q; + BOOL flag; + int n, ch; +(IGNORED) fseek(cache_files, 0L, `<abs file addr`>); +ch = (int) getc(cache_files); +while ( ch != EOF ){ + if ( ch == ' ' ) { `<cache-dir = cache record`> } + else { `<flag = (file == cache record)`> + if( flag ){ + `<flag = (cache-dir == env-dir)`> + if( flag ){ `<open file and, if success, return`> } + } } + if ( ch != EOF ){ ch = (int) getc(cache_files); } +} +>>> + +\<cache-dir = cache record\><<< +q = cache_dir; +do + *(q++) = ch = (int) getc(cache_files); +while( (ch !='\n') && (ch != EOF) ); +*(q-1 - (*(q-2) == `<directory '/'`>) +#ifdef DOS_WIN32 + - (*(q-2) == '/') +#endif + ) = '\0'; +>>> + +\<flag = (file == cache record)\><<< +p = name; flag = FALSE; +while( *(p++) == ch ){ + ch = (int) getc(cache_files); +} +if( (*(p-1) == '\0') && ((ch == '\n') || (ch == EOF)) ){ flag = TRUE; } +else{ + while( (ch != '\n') && (ch != EOF) ) { ch = (int) getc(cache_files); } +} +>>> + +\<flag = (cache-dir == env-dir)\><<< +flag = FALSE; +(IGNORED) fseek(dot_file, 0L, `<abs file addr`>); +while( search_dot_file( typ ) && !flag ){ U_CHAR *q, save_ch; + int n, m; + q = dot_dir; + do + *(q++) = ch = (int) getc(dot_file); + while( (ch !='\n') && (ch != EOF) ); + flag = *(q - 2) = '!'; + q -= (flag? 2 : 1); + *(q - (*(q-1) == `<directory '/'`>) +#ifdef DOS_WIN32 + - (*(q-1) == '/') +#endif + ) = '\0'; + if( (n = strlen((char *) dot_dir)) > (m = strlen((char *) cache_dir)) ){ flag = FALSE; } + else { + save_ch = *(cache_dir + n); + *(cache_dir + n) = '\0'; + flag = eq_str(dot_dir,cache_dir) && ( flag || (m == n) ); + *(cache_dir + n) = save_ch; + } +} +>>> + +\<open file and, if success, return\><<< +n = (int) strlen((char *) cache_dir); +cache_dir[n] = dir_path_slash(cache_dir); +cache_dir[n+1] = '\0'; +(IGNORED) strcat((char *) cache_dir, (char *) name); +>>> + +\<BROKEN\><<< +if( (file = f_open(cache_dir,flags)) == NULL ) { + warn_i_str( 47, cache_dir); +} else { + return file; +} +>>> + + + +\SubSection{Store New Auxiliary Cache} + + +\<set new cache file\><<< +if( tex4ht_fls ){ + FILE *in_file, *out_file; + U_CHAR temp_file[256]; + `<set temp file`> + `<backup cache file`> + if( (out_file = fopen(tex4ht_fls_name, WRITE_TEXT_FLAGS)) == NULL ) + { bad_in_file(tex4ht_fls_name); + } else { + if( (in_file = fopen(temp_file, READ_TEXT_FLAGS)) != NULL ){ + `<output into new cache`> + (IGNORED) fclose(in_file); + } + (IGNORED) fclose(out_file); +} } +>>> + + + + + +\<set temp file\><<< +(IGNORED) strcpy((char *) temp_file, (char *) job_name); +temp_file[job_name_n] = '\0'; +temp_file[job_name_n-1] = 'p'; +temp_file[job_name_n-2] = 'm'; +temp_file[job_name_n-3] = 't'; +>>> + + + + + + + +\<vars\><<< +#ifndef KPATHSEA +static BOOL tex4ht_fls = FALSE; +static char *tex4ht_fls_name = (char *) 0; +#endif +>>> + +\<cat /\><<< +#if defined(DOS_WIN32) || defined(__DJGPP__) + (is_forward_slash(files_cache)? "/" : "\\" ) +#else + "/" +#endif +>>> + +\<get dir of tex4ht.fls\><<< +{ U_CHAR *p; + if( !tex4ht_fls_name ){ + tex4ht_fls_name = p = files_cache; + (IGNORED) fseek(dot_file, 0L, `<abs file addr`>); + if ( search_dot_file( 'l' ) ){ + do + *(p++) = ch = (int) getc(dot_file); + while( (ch !='\n') && (ch != EOF) ); + p--; *p = '\0'; + } else { (IGNORED) strcpy((char *) p, +(char *) getenv("TEX4HTWR")? "~~/tex4ht.fls" : "tex4ht.fls"); + } + } + `<relative tex4ht.fls addr`> +} +>>> + + +\<relative tex4ht.fls addr\><<< +if( *tex4ht_fls_name == '~' ){ + tex4ht_fls_name = abs_addr(tex4ht_fls_name,getenv("TEX4HTWR")); +} +>>> + + + +\<relative tex4ht.fls addrNO\><<< +if( *tex4ht_fls_name == '~' ){ + `<fls temp var`> + if( HOME_DIR ){ + (IGNORED) strcpy((char *) p, (char *) tex4ht_fls_name+1); + (IGNORED) sprintf(files_cache,"%s%s", HOME_DIR, p); + } else { + (IGNORED) strcpy((char *) files_cache, "tex4ht.fls"); + } + tex4ht_fls_name = files_cache; +} +>>> + +\<fls var\><<< +U_CHAR files_cache[PATH_MAX]; +>>> + +\<fls temp var\><<< +U_CHAR p[PATH_MAX]; +>>> + +\<vars\><<< +static U_CHAR *HOME_DIR; +>>> + +\<main's init\><<< +HOME_DIR = getenv("HOME"); +>>> + +We might want more than one version of \`'tex4ht.fls', for different +combinations of subtrees of htf fonts. + +\<get tex4ht.fls from com ln\><<< +#ifndef KPATHSEA +tex4ht_fls_name = p+2; +#endif +>>> + + + +\<backup cache file\><<< +if( (out_file = fopen(temp_file, WRITE_TEXT_FLAGS)) == NULL ) +{ bad_in_file(temp_file); +} else { + if( (in_file = fopen(tex4ht_fls_name, READ_TEXT_FLAGS)) != NULL ){ + int ch; + while( (ch = getc(in_file)) != EOF ) { + (IGNORED) putc( ch, out_file ); + } + (IGNORED) fclose(in_file); + } + (IGNORED) fclose(out_file); +} +>>> + + +\<output into new cache\><<< + U_CHAR dir[255], prev_dir[255], file[255], *p; + int ch; + BOOL is_dir; + struct cache_file_rec *file_rec, *prev_file_rec; +cur_cache_font = cache_font; +ch = 'n'; prev_dir[0] = '\0'; +while( ch != EOF ){ + ch = getc(in_file); + is_dir = (ch == ' '); + p = is_dir? dir : file; + while( ch != '\n' ) { + if( ch == EOF ) break; + if( ch != ' ' ) { *p++ = ch; } + ch = getc(in_file); + } + *p = '\0'; + if( is_dir && (dir[0] != '\0') ){ + `<output smaller internal directories`> + (IGNORED) fprintf(out_file," %s\n", dir); + (IGNORED) strcpy((char *) prev_dir, (char *) dir); + } else if( !is_dir && (file[0] != '\0') ){ + `<output smaller internal files`> + (IGNORED) fprintf(out_file,"%s\n", file); + } +} +`<output remainder of internal cache`> +>>> + + +\<output smaller internal directories\><<< +while( cur_cache_font != (struct cache_font_rec *)0 ){ + if( gt_str(dir,cur_cache_font->dir) ){ + `<cache directory in external memory`> + } else break; + cur_cache_font = cur_cache_font->next; +} +>>> + + +\<cache directory in external memory\><<< +file_rec = cur_cache_font->cache_file; +if( file_rec ){ + if( !eq_str( prev_dir, cur_cache_font->dir) ){ + (IGNORED) fprintf(out_file, " %s\n", cur_cache_font->dir); + (IGNORED) strcpy((char *) prev_dir, (char *) dir); + } + cur_cache_font->cache_file = (struct cache_file_rec *) 0; + while( file_rec ) { + prev_file_rec = file_rec; + file_rec = file_rec->next; + (IGNORED) fprintf(out_file, "%s\n", prev_file_rec->file); + free((void *) prev_file_rec ); + } +} +>>> + + + + +\<output smaller internal files\><<< +if( cur_cache_font != (struct cache_font_rec *)0 ){ + if( eq_str(dir,cur_cache_font->dir) ){ + file_rec = cur_cache_font->cache_file; + while( file_rec ) { + if( gt_str(file_rec->file,file) ){ break; } + else if( gt_str(file,file_rec->file) ){ + (IGNORED) fprintf(out_file, "%s\n", file_rec->file); + } + prev_file_rec = file_rec; + file_rec = file_rec->next; + free((void *) prev_file_rec ); + } + cur_cache_font->cache_file = file_rec; + } +} +>>> + + + +\<output remainder of internal cache\><<< +while( cur_cache_font != (struct cache_font_rec *)0 ){ + `<cache directory in external memory`> + cur_cache_font = cur_cache_font->next; +} +>>> + + + + + + + + +\<vars\><<< +#ifndef KPATHSEA +static FILE* cache_files; +#endif +>>> + +\<open old cache file\><<< +cache_files = f_open(tex4ht_fls_name, READ_BIN_FLAGS); +>>> + +\<close old cache file\><<< +if( cache_files != (FILE *) 0 ){ (IGNORED) fclose(cache_files); } +>>> + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Export TEX4HTFONTSET for kpathsea} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Background} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + + + +A system call similar to \`'TEX4HTFONTSET={...}; export TEX4HTFONTSET' +is issued for ordering searches of htf fonts by kpathsea. + + +The system call assumes a pattern of the form \`'.....%%12...' +in the argument -DTEX4HTFONTSET provided to the compilation of tex4ht. +If none is provided, a default pattern is assumed. + +To allow also opposite order of search, the +code should modify to answer also for patterns of the form +\`'.....%%21...'. + + +\Verbatim +The i-records (provided e.g., in tex4ht.env) are assumed to refer to +paths relative to the ht-fonts directory. If a record happens to +include the substring `/ht-fonts/', then only the portion that follows +that substring is considered. + +For instance, the records + + i~/tex4ht.dir/ht-fonts/iso8859/1/! + i~/tex4ht.dir/ht-fonts/alias/! + +are equivalent to + + iiso8859/1 + ialias + + + +If i-records are not provided, a ht-like script may contain +a call similar to + + test -z "$3" || TEX4HTFONTSET=$3;export TEX4HTFONTSET +on unix and + + set TEX4HTFONTSET={%%12} + +on windows. + +In texmf.cnf: TEX4HTFONTSET=iso8859/1,alias + + + TEX4HTFONTSET={iso8859/1,alias}; export TEX4HTFONTSET + set TEX4HTFONTSET={iso8859/1,alias} +\EndVerbatim + + + The user has two options of hand-made entries: i-records and + exportation. Tex4ht assumes the following priority schema: + + +\List{1} +\item + Entries provided in i-records (e.g., within tex4ht.env) +\item Entries exported by TEX4HTFONTSET from scripts (e.g., in htlatex) +\item Entries hard wired in TEX4HTFONTSET within texmf.cnf +(In such a case, i-records should not be provided. That is, in + the default setting, i-records should not be provided in tex4ht.env, + within tex4ht.c, or over tex4ht.c (in the ht... scripts). Users may + add such records, but the default installations should not contain + i-records.) +\EndList + + +xputenv() is a kpathsea routine for writing environment variables + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Collect Information} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<export TEX4HTFONTSET\><<< +#ifdef KPATHSEA +{ char str [256], *export_str, *postfix; + export_str = m_alloc(char, 1); + *export_str = '\0'; + `<set the exported list`> + if( (int) strlen((char *) export_str) > 0 ){ + (IGNORED) strcpy((char *) str, "%%12"); + export_str = (char *) r_alloc((void *) export_str, + (int) strlen((char *) export_str) + (int) strlen((char *) str) + 1 ); + postfix = str - 1; + while( *(++postfix) != '\0' ){ + if( (*postfix=='%') && (*(postfix+1)=='%') && + (*(postfix+2)=='1') && (*(postfix+3)=='2') ){ + *postfix='\0'; postfix += 4; break; + } } + if( (int) strlen((char *) export_str) != 0 ){ + `<insert export into pattern`> + `<system call for export`> + } + } + `<recording TEX4HTFONTSET`> + free((void *) export_str); + `<debug info about TEX4HTFONTSET`> +} +#endif +>>> + + + + +\<insert export into pattern\><<< +{ char *from_ch; + int i, n, m; + n = (int) strlen((char *) str); + m = (int) strlen((char *) export_str); + from_ch = export_str + m; + for( i = 0; i<=m; i++){ + *(from_ch + n) = *(from_ch); + from_ch--; + } + for( i = 0; i<n; i++){ + export_str[i] = str[i]; + } + (IGNORED) strcat((char *) export_str, (char *) postfix); +} +>>> + +An entry similar to the following one is assumed in texmf.cnf. + +\Verbatim +TEX4HTINPUTS=.;$TEXMF/tex4ht/base//;$TEXMF/tex4ht/ht-fonts/{$TEX4HTFONTSET}// +\EndVerbatim + + + +\<system call for export\><<< +{ U_CHAR * q; + if( dump_htf_search ) { U_CHAR *p, *q; + `<trace TEX4HTFONTSET`> + } + q = (U_CHAR *) kpse_var_value( "TEX4HTFONTSET" ); + if( q ){ + xputenv("TEX4HTFONTSET", export_str); + if( dump_htf_search ){ + (IGNORED) printf("setting TEX4HTFONTSET={%s}\n", export_str); + } + } else if( dump_htf_search ) { + warn_i_str( 50, "TEX4HTFONTSET for kpathsea" ); + } +} +>>> + + + + + + +\List{*} +\item + in the directories stated within `-i' switches of the tex4ht command line +\item + in the directories specified within `i' records of the env file +\item + in a directory compiled into tex4ht during its compilation +\EndList + + +\<set the exported list\><<< +{ + struct htf_com_rec *q; + q = htf_font_dir; + while( q != (struct htf_com_rec *) 0 ){ + (IGNORED) strcpy((char *) str, (char *) q->name); + export_htf( &export_str, str ); + q = q->next; +} } +(IGNORED) fseek(dot_file, 0L, `<abs file addr`>); +while ( search_dot_file( 'i' ) ){ + int ch; + char* p; + p = str; + do { + ch = (int) getc(dot_file); + if( ch != EOF) { *(p++) = ch;} + } while( (ch !='\n') && (ch != EOF) ); + *p = '\0'; + export_htf( &export_str, str ); +} +#ifdef HTFDIR + (IGNORED) strcpy((char *) str, (char *) HTFDIR); + export_htf( &export_str, str ); +#endif +`<pre assigned TEX4HTFONTSET`> +>>> + + + +\<pre assigned TEX4HTFONTSET\><<< +{ U_CHAR * q; + q = (U_CHAR *) kpse_var_value( "TEX4HTFONTSET" ); + if( q ){ + if( (int) strlen((char *) q) > 0 ){ + export_str = (char *) r_alloc((void *) export_str, + (int) strlen((char *) export_str) + (int) strlen((char *) q) + 2); + if( (int) strlen((char *) export_str) > 0 ){ + (IGNORED) strcat((char *) export_str, ","); + } + (IGNORED) strcat((char *) export_str, (char *) q); +} } } +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Appending a Segment} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<header functions\><<< +#ifdef KPATHSEA +static void export_htf( ARG_II(char**, char[]) ); +#endif +>>> + +\<functions\><<< +#ifdef KPATHSEA +`[ +static void export_htf(export_str, str) + char** export_str `; + char str[] +;{ int i; + char* p; + BOOL found; + i = (int) strlen((char *) str) - 1; + while( (i>=0) && (str[i] == '\n') ){ str[i--] = '\0'; } + while( (i>=0) && (str[i] == ' ') ) { str[i--] = '\0'; } + if( (i>=0) && (str[i] == '!') ){ str[i--] = '\0'; } + if( (i>=0) && ((str[i] == '/') || (str[i] == '\\')) ){ + str[i--] = '\0'; } + i -= 8; found = FALSE; + while( --i>=0 ){ + if( ((str[i] == '/') || (str[i] == '\\')) && (str[i+1]== 'h') + && (str[i+2]=='t') && (str[i+3]=='-') + && (str[i+4]=='f') && (str[i+5]=='o') + && (str[i+6]=='n') && (str[i+7]=='t') + && (str[i+8]=='s') + && ((str[i+9] == '/') || (str[i+9] == '\\')) + ){ + p = str + i + 10; i=0; + while( *p ){ str[i++] = *(p++); } + str[i] = '\0'; + found = TRUE; break; + } } + if( found ){ + *export_str = (char *) r_alloc((void *) *export_str, + (int) strlen((char *) *export_str) + (int) strlen((char *) str) + 2 ); + if( (int) strlen((char *) *export_str) > 0 ){ + (IGNORED) strcat((char *) *export_str, ","); + } + (IGNORED) strcat((char *) *export_str, (char *) str); + } +} +#endif +>>> + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Recording TEX4HTFONTSET} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +Kpathsea ignores the under ht-fonts paths requests coming from tex4ht.c, +exported like in \`'TEX4HTFONTSET={mozilla,iso8859/1,alias,unicode}'. +So tex4ht.c lets kpathsea find whatever path it likes, such as + +\Verbatim +/n/gold/5/gurari/tex4ht.dir/texmf/tex4ht/ht-fonts/iso8859/1/cm/cmr.htf +\EndVerbatim + +and then tex4ht.c tries to fix the path based on the information it +collected for TEX4HTFONTSET, + +\Verbatim +/n/gold/5/gurari/tex4ht.dir/texmf/tex4ht/ht-fonts/unicode/cm/cmr.htf +\EndVerbatim + + +To that end, tex4ht.c breaks the first approximation to head +\`'.../ht-fonts/' and tail \`'....htf', while removing the path +segment \`'iso8859' just after \`'ht-fonts/'. + +Then, tex4ht.c tries the intermediate path segments from +\`'TEX4HTFONTSET={mozilla,iso8859/1,alias,unicode}', possibly with +removing prefixes from tail. + + +\<vars\><<< + +#ifdef KPATHSEA +static char * export_str_chars = (char *) 0; +#endif +>>> + +\<scan fonts vars\><<< + +#ifdef KPATHSEA +`<scan kpathsea vars`> +#endif +>>> + + + + +\<recording TEX4HTFONTSET\><<< +{ int n; + n = (int) strlen((char *) export_str); + if( n > 0 ){ + export_str_chars = m_alloc(char, n+1); + (IGNORED) strcpy((char *) export_str_chars, (char *) export_str); +} } +>>> + + +\<scan kpathsea vars\><<< +int cardinality=0; +char ** fontset=0; +>>> + +\<start loading fonts\><<< + +#ifdef KPATHSEA +if( export_str_chars ){ + `<decompose TEX4HTFONTSET`> +} +#endif +>>> + + +\<end loading fonts\><<< + +#ifdef KPATHSEA +if( export_str_chars ){ + free((void *) export_str_chars); + free((void *) fontset); +} +#endif +>>> + + +\<decompose TEX4HTFONTSET\><<< +{ U_CHAR *p; + int n; + cardinality = 1; + p = (U_CHAR *) export_str_chars; + while( *p != '\0' ){ + if( *p == ',' ){ cardinality++; } + p++; + } + fontset = m_alloc(char *, cardinality); + p = (U_CHAR *) export_str_chars; + fontset[0] = p; + n=1; + while( *p != '\0' ){ + if( *p == ',' ){ fontset[n++] = p+1; *p = '\0'; } + p++; +} } +>>> + + +\<correct htfname\><<< +{ U_CHAR * head, * tail, *p; + int n; + `<decompose htfname`> + htfname = (U_CHAR *) 0; + `<try alternative htfname`> +} +>>> + + +\<decompose htfname\><<< +n = (int) strlen((char *) htfname); +tail = head = m_alloc(char, n+1); +(IGNORED) strcpy((char *) head, (char *) htfname); +while( n>11 ){ + if( (*tail=='\\') || (*tail=='/') ){ + if( (*tail == *(tail+9)) && (*(tail+1) == 'h') + && (*(tail+2) == 't') && (*(tail+3) == '-') + && (*(tail+4) == 'f') && (*(tail+5) == 'o') + && (*(tail+6) == 'n') && (*(tail+7) == 't') + && (*(tail+8) == 's') ){ + p = tail + 9; *(tail + 10) = '\0'; tail += 11; + while( (*tail != *p) && (*tail != '\0') ){ tail++; } + break; + } } + tail++; n--; +} +>>> + + + + +\<try alternative htfname\><<< +for( n = 0 ; (n < cardinality) && !htfname ; n++){ + p = tail; + while( *p != '\0' ){ + char * s, *nm; + s = m_alloc(char, (int) strlen((char *) head ) + + (int) strlen((char *) fontset[n] ) + + (int) strlen((char *) p ) + 1); + (IGNORED) strcpy((char *) s, (char *) head); + (IGNORED) strcat((char *) s, (char *) fontset[n]); + (IGNORED) strcat((char *) s, (char *) p); + nm = kpse_find_file (s, kpse_program_text_format, 0); + free((void *) s); + if ( nm ){ + htfname = nm; break; + } + p++; + while( (*p != '\\') && (*p != '/') && (*p != '\0') ){ p++; } +} } +>>> + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Debugging info} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<debug info about TEX4HTFONTSET\><<< +if( dump_htf_search || dump_env_search ) { + U_CHAR *p, *q; + `<trace TEX4HTINPUTS`> +} +>>> + + +NOTE: The following code, activated by -hV or -hF, stops tex4ht.c with +and error under miktex/kpathse. +The execution arrives to +`\Verb+kpse_find_file ( "texmf.cnf", kpse_cnf_format, 0);+' +but does not print a message in the line that follows. The problem +probably was in \Verb=warn_i_str=. The code was modified from + +\Verbatim + static U_CHAR warning[] = "--- warning --- "; + .... + fprintf(stderr,"--- warning --- "); +\EndVerbatim + +to + +\Verbatim + fprintf(stderr,"--- warning --- "); +\EndVerbatim + +with the assumption/hope that it will take care of the problem. + + +\<trace TEX4HTINPUTS\><<< +p = kpse_find_file ( "texmf.cnf", kpse_cnf_format, 0); +if( p ){ + (IGNORED) printf( "texmf.cnf = %s\n", p); +} else { warn_i_str(1, "texmf.cnf" ); } +p = (U_CHAR *) kpse_var_value( "TEX4HTINPUTS" ); +if( p ){ + (IGNORED) printf("TEX4HTINPUTS = %s\n", p); +} +q = getenv("TEX4HTINPUTS"); +if( q ){ (IGNORED) printf( + "Environment var TEX4HTINPUTS: %s\n", q); +} +if( !p && !q ){ + (IGNORED) printf( "Missing TEX4HTINPUTS for kpathsea\n" ); +} +>>> + + + + + +\<trace TEX4HTFONTSET\><<< +p = (U_CHAR *) kpse_var_value( "TEX4HTFONTSET" ); +if( p ){ + (IGNORED) printf("given TEX4HTFONTSET = %s\n", p); +} +q = getenv("TEX4HTFONTSET"); +if( q ){ (IGNORED) printf( + "Environmet var TEX4HTFONTSET: %s\n", q); +} +if( !p && !q ){ + (IGNORED) printf( "Missing TEX4HTFONTSET for kpathsea\n" ); +} +>>> + + + + + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Searching with KPATHSEA} +%%%%%%%%%%%%%%%%%%%%%% + +\Link[http://www.fptex.org/kpathsea/kpathsea\string_toc.html]{}{}Kpathsea +manual\EndLink + + +\<h-include\><<< +`<KPATHSEA h-include`> +>>> + + + +\<kpathsea arg 0\><<< + +#ifdef KPATHSEA + kpse_set_program_name (argv[0], "tex4ht"); +#endif +>>> + + + +\<kpathsea env file\><<< + +#ifdef KPATHSEA +if( !dot_file ) { U_CHAR * envfile; + char *arch, *p, str[256]; + `<arch = tail of SELFAUTOLOC`> + envfile = (char *) 0; + `<envfile = kpse-find-file architecture/tex4ht.env`> + if ( !envfile ){ `<envfile = kpse-find-file tex4ht.env`> } + if ( !envfile ){ `<envfile = kpathsea tex4ht.env`> } + if ( envfile ){ + dot_file = kpse_open_file (envfile, + kpse_program_text_format); + (IGNORED) printf("(%s)\n", envfile); + } else if( dump_env_search ){ + p = (char *) kpse_var_value( "TEX4HTINPUTS" ); + if( p ){ + (IGNORED) printf( "TEX4HTINPUTS = %s\n", p ); + } else { warn_i_str( 50, "kpathsea variable TEX4HTINPUTS"); } + } +} +#endif +>>> + +The location of tex4ht.c can be found from the kpathsea variable +`SELFAUTOLOC = /n/gold/5/gurari/tex4ht.dir/bin/solaris', from which +one can determine the architecture in use. + + +\Verbatim + > I still cannot catch why you need to determine the architecture, since + > all stuff belongs to texmf tree which is always the same for all systems, + > and tex4ht.env is found without problem. + > And T4HTINPUTS= should be set in texmf.cnf + +In case we have different tex4ht.env files for different architectures + + /usr/TeX/texmf/tex4ht/base/i386-linux/tex4ht.env + /usr/TeX/texmf/tex4ht/base/win32/tex4ht.env + +the SELFAUTOLOC provides us information about the architecture in use +by inspecting from what branch tex4ht.c comes + + /usr/TeX/bin/i386-linux + /usr/TeX/bin/win32 + +Seems to me that this problem is solved now. + +\EndVerbatim + + + +\<arch = tail of SELFAUTOLOC\><<< +p = arch = (char *) kpse_var_value( "SELFAUTOLOC" ); +while( *p != '\0' ){ + if( (*p == '/') || (*p == '\\') ){ + arch = p; + } + p++; +} +>>> + + +\<envfile = kpse-find-file architecture/tex4ht.env\><<< +if( arch ){ + (IGNORED) sprintf(str,"%s%ctex4ht.env", arch+1, *arch); + if( dump_env_search ){ + (IGNORED) printf("kpse_open_file (\"%s\", ...)?\n", str ); + } + envfile= kpse_find_file (str, kpse_program_text_format, 0); +} +>>> + + +\<envfile = kpse-find-file tex4ht.env\><<< +if( dump_env_search ){ + (IGNORED) printf("kpse_open_file (\"tex4ht.env\", ...)?\n"); +} +envfile= kpse_find_file ("tex4ht.env", kpse_program_text_format, 0); +>>> + + + + +\<if kpathsea tfm files else\><<< +#ifdef KPATHSEA +{ + U_CHAR * tfmfile; + tfmfile = kpse_find_file (file_name, kpse_tfm_format, 0); + if( !tfmfile ){ `<tfmfile = kpathsea tfm file`> } + if ( tfmfile ){ + (IGNORED) printf("(%s)\n", tfmfile); + font_file = kpse_open_file (tfmfile, kpse_tfm_format); + } +} +#else +>>> + +% font_file = kpse_open_file (file_name, kpse_tfm_format); + + +\<endif kpathsea tfm files\><<< +#endif +>>> + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{kpathsea vs kpse-find-file} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +The \`'kpsewhich' utility can succeed where the \Verb|kpse_find_file| +function fails, if the program is named something other than \`'tex4ht'. +Otherwise, we don't find the \`'TEX4HTINPUTS' definition in +\`'texmf.cnf'. + +However, this is not yet enough to actually make the program work under +an arbitrary name, because the \`'.htf' lookups fail; we need to reset +the Kpathsea progname. Other things to do, so let it stand. Bottom +line is that the program must be invoked as \`'tex4ht'. + + + +\<envfile = kpathsea tex4ht.env\><<< +#define KPSEWHICH_CMD "kpsewhich --progname=tex4ht --format=othertext tex4ht.env" +if( dump_env_search ){ + (IGNORED) printf("system(" KPSEWHICH_CMD ")?\n"); /* cpp concatenation */ +} +if( system(KPSEWHICH_CMD ">tex4ht.tmp") == 0 ){ + `<fileaddr = read tex4ht.tmp`> + envfile= kpse_find_file (fileaddr, kpse_program_text_format, 0); + if( envfile ){ + warn_i_str( 50, + "search support for kpse_find_file--using kpsewhich calls instead"); +} } +>>> + +\<tfmfile = kpathsea tfm file\><<< +char s [256]; +(IGNORED) strcpy(s, "kpsewhich "); +(IGNORED) strcat(s, file_name); +(IGNORED) strcat(s, " > tex4ht.tmp "); +if( system(s) == 0 ){ + `<fileaddr = read tex4ht.tmp`> + tfmfile = kpse_find_file (fileaddr, kpse_program_text_format, 0); +} +>>> + + +Don't know how to avoid the use of intermediate file: popen(...) and +fork() are not stadard utilities. Also the redirection \Verb+>+ might +need to be changed, e.g., to \Verb+>&+. + +\<fileaddr = read tex4ht.tmp\><<< +char fileaddr [256]; +int loc = 0; +FILE* file = f_open("tex4ht.tmp", READ_TEXT_FLAGS); +if( file ){ + while( (fileaddr[loc] = getc(file)) >=0 ){ + if( fileaddr[loc] == '\n' ){ fileaddr[loc] = '\0'; break; } + loc++; + } + (IGNORED) fclose(file); +} +>>> + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{HTF Fonts} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + \<vars\><<< +static BOOL dump_htf_search = FALSE; +>>> + +\<trace htf search\><<< +dump_htf_search = TRUE; +>>> + + + + +\<file = kpathsea .htf file\><<< + +#ifdef KPATHSEA + if( !file ){ U_CHAR * htfname; + htfname= kpse_find_file (name, kpse_program_text_format, 0); + if ( htfname ){ + `<correct htfname`> + if ( htfname ){ + (IGNORED) printf("(%s)\n", htfname); + file= fopen(htfname,READ_TEXT_FLAGS); + } } + } +#endif +>>> + +web2c/kpathsea version uses texmf.cnf with the following: + +\Verbatim +TEX4HTFONTSET=alias,iso8859 +TEX4HTINPUTS=.;$TEXMF/tex4ht/base//;$TEXMF/tex4ht/ht-fonts/{$TEX4HTFONTSET}// +T4HTINPUTS=.;$TEXMF/tex4ht/base// +\EndVerbatim + +We can check values of variables of kpathsea with code fragments of +the following form. + +\Verbatim +if( q = (U_CHAR *) kpse_var_value( "TEX4HTINPUTS" ) ){ + (IGNORED) printf( "%s\n", q ); +} +\EndVerbatim + + + + + +\ifHtml[\HPage{more}\Verbatim +I'm trying to get tex4ht to work with the kpathsea libraries. +Unfortunately, it seems to be having problems finding tfm files, even +when the relevant tex environment variables appear to have been set +and the file exists: + +mclellan:~/test% kpsewhich -progname=tex4ht cmsy10.tfm +/usr/local/tex/texmf/fonts/tfm/public/cm/cmsy10.tfm +mclellan:~/test% ls -l `kpsewhich -progname=tex4ht cmsy10.tfm` +-rw-r--r-- 1 tetex local 1124 Aug 14 1995 /usr/local/tex/texmf/fonts/tfm/public/cm/cmsy10.tfm + +The OS is solaris 7, and I compiled tex4ht as follows: +gcc -O2 -DKPATHSEA -I/usr/local/teTeX/include -L/usr/local/teTeX/lib -o tex4ht tex4ht.c -DHAVE_DIRENT_H -lkpathsea +% +tex4ht: fatal: tfm file `cmtt10.tfm' not found. +% +\EndVerbatim\EndHPage{}]\fi +% +\ifHtml[\HPage{kpathsea note}\Verbatim +Date: Mon, 22 Dec 1997 13:06:18 +0000 + +There is an issue to resolve, which is how tex4ht finds its support +files, viz its tex4ht.env control file (in which the font-finding +lines are now ignored), and its .htf files. For the present, I have +set it up so that these are searched for on the TEXINPUTS path, and I +have located them in $TDS/tex/generic/tex4ht/base and +$TDS/tex/generic/tex4ht/htf. Ideally, we would invent a new font +category of "htf" to parallel vf, tfm etc, but that is quite a +widespread change to implement. Any views on that sort of thing, Olaf? +\EndVerbatim\EndHPage{}]\fi{} +\ifHtml[\HPage{more}\Verbatim +Date: Tue, 30 Dec 1997 21:32:40 +0000 + + + + > b) Insert the following definition at the beginning of the source file + > + > #ifdef KPATHSEA + > #define ENVFILE "...dir_in_kpathsea.../tex4ht.env" + > #endif + > +kpathsea's system allows for programs to locate files depending on the +location of binaries, so anything hard-wired would not work + +\EndVerbatim\EndHPage{}]\fi + +\ifHtml[\HPage{more}\Verbatim +Subject: tex4htk search paths. +Date: 04 Feb 1998 21:22:46 +0100 + +Lines: 43 +X-Mailer: Gnus v5.4.66/Emacs 19.34 + +I'm wondering whether the texmf tree really is the proper place for +the tex4htk.env and .htf files. Unless these need to be read by TeX, +the proper location would be somewhere in + texmf/tex4htk/ +which is accessible by using kpse_program_text_format (or +kpse_program_binary_format) in the kpse_find_file calls, and can be +modified by defining TEX4HTKINPUTS in texmf.cnf or the environment. + + +If so, the necessary changes would look something like this... + +--- tex4ht.c- Fri Jan 30 17:00:55 1998 ++++ tex4ht.c Wed Feb 4 21:20:33 1998 +@@ -3038,7 +3038,7 @@ + char *p, *q, *in_name = "", *out_name = ""; + + #ifdef KPATHSEA +- kpse_set_progname (argv[0]); ++ kpse_set_program_name (argv[0], NULL); + #endif + + +@@ -3175,7 +3175,7 @@ + + #ifdef KPATHSEA + if( !dot_file ) +- dot_file = kpse_open_file ("tex4ht.env", kpse_tex_format); ++ dot_file = kpse_open_file ("tex4ht.env", kpse_program_text_format); + #endif + + +@@ -3648,7 +3648,7 @@ + + #ifdef KPATHSEA + if( !file ){ char * htfname; +- htfname= kpse_find_file (name, kpse_tex_format, 0); ++ htfname= kpse_find_file (name, kpse_program_text_format, 0); + if ( htfname) file= fopen(htfname,READ_TEXT_FLAGS); + } + #endif + +-- +Olaf Weber + +\EndVerbatim\EndHPage{}]\fi +% +\ifHtml[\HPage{more}\Verbatim + > kpathsea was a valuable addition when tex4ht.c had not a booking + > mechanism of its own. It looks like we are getting to a point + > where we need to reevaluate the role of kpathsea within tex4ht.c. + +the advantage of kpathsea is that it continues to work if you move the +entire TeX tree to a new disk, or the like. anything like tex4ht.env, +which has path names in it, cannot work eg on a mounted CD (where you +cannot predict the path) + +\EndVerbatim\EndHPage{}]\fi +% +\ifHtml[\HPage{more}\Verbatim +I have +changed the second argument of 'kpse_set_program_name' from NULL (which would +effectively mean argv[0]) to 'tex4ht', as that saves having to add a +'T4HTINPUTS' (or 'T4HTKINPUTS') variable into the kpathsea configuration file +'texmf.cnf' pointing to the same place for 'tex4ht.env' as the 'TEX4HTINPUTS' +variable. + +0a1,4 +> /* t4htk.c = t4ht.c, but with KPATHSEA support +> * corrected/adjusted by Andrew Gray <ajpg@debian.org>, +> * 11 March 1999 +> */ +94a99,102 +> #ifdef KPATHSEA +> #include <kpathsea/progname.h> +> #include <kpathsea/tex-file.h> +> #endif +943c951 +< kpse_set_program_name (argv[0], NULL); +--- +> kpse_set_program_name (argv[0], ``tex4ht''); +\EndVerbatim\EndHPage{}]\fi +% +\ifHtml[\HPage{more}\Verbatim +I'm trying to get tex4ht to work with the kpathsea libraries. +Unfortunately, it seems to be having problems finding tfm files, even +when the relevant tex environment variables appear to have been set +and the file exists: + +mclellan:~/test% kpsewhich -progname=tex4ht cmsy10.tfm +/usr/local/tex/texmf/fonts/tfm/public/cm/cmsy10.tfm +mclellan:~/test% ls -l `kpsewhich -progname=tex4ht cmsy10.tfm` +-rw-r--r-- 1 tetex local 1124 Aug 14 1995 /usr/local/tex/texmf/fonts/tfm/public/cm/cmsy10.tfm + +The OS is solaris 7, and I compiled tex4ht as follows: +gcc -O2 -DKPATHSEA -I/usr/local/tex/include -L/usr/local/tex/lib -o tex4ht tex4ht.c -DHTFDIR='"/usr/contrib/share/tex4ht"' -DHAVE_DIRENT_H -lkpathsea + +tex4ht.c (2000-03-01-16:28) +/usr/contrib/share/tex4ht/tex4ht: fatal: tfm file `cmsy10.tfm' not found. + +\EndVerbatim\EndHPage{}]\fi +% +\ifHtml[\HPage{more}\Verbatim + 1. Call `kpse_set_program_name' with `argv[0]' as the first argument; + the second argument is a string or `NULL'. The second argument is + used by Kpathsea as the program name for the `.PROGRAM' feature of + config files (*note Config files::.). If the second argument is + `NULL', the value of the first argument is used. This function + must be called before any other use of the Kpathsea library. + + If necessary, `kpse_set_program_name' sets the global variables + `program_invocation_name' and `program_invocation_short_name'. + These variables are used in the error message macros defined in + `kpathsea/lib.h'. It sets the global variable `kpse_program_name' + to the program name it uses. It also initializes debugging + options based on the environment variable `KPATHSEA_DEBUG' (if + that is set). Finally, it sets the variables `SELFAUTOLOC', + `SELFAUTODIR' and `SELFAUTOPARENT' to the location, parent and + grandparent directory of the executable, removing `.' and `..' + path elements and resolving symbolic links. These are used in the + default configuration file to allow people to invoke TeX from + anywhere, specifically from a mounted CD-ROM. (You can use + `--expand-var=\$SELFAUTOLOC', etc., to see the values finds.) + +\EndVerbatim\EndHPage{}]\fi + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Searching Utilities} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Search Files Listed in Environment File} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +The following is used for start searching files from directories mentioned +in the dot file. + +\<header functions\><<< +static FILE* search_in_dot_file( ARG_IV( int, const U_CHAR *, const U_CHAR *, + struct env_var_rec *) ); +>>> + +\<functions\><<< +`[ +static FILE* search_in_dot_file( typ, name, flags, env_dirs) + int typ`; + const U_CHAR *name`; + const U_CHAR *flags`; + struct env_var_rec *env_dirs + +;{ U_CHAR *ch, dir[256]; + FILE* file; +#ifndef KPATHSEA + if( cache_files != (FILE *) 0 ){ + `<search font in cache files`> + } +#endif + (IGNORED) fseek(dot_file, 0L, `<abs file addr`>); + while( search_dot_file( typ ) ){ + ch = dir; + while((*(ch++) = (int) getc(dot_file)) > ' '); + while(*(ch-1) != '\n'){ + *(ch-1) = (int) getc(dot_file); + } + *(ch-1) = '\0'; + file = search_file_base(name, dir, flags, env_dirs); + if( file != NULL ){ +#ifndef KPATHSEA + tex4ht_fls = TRUE; +#endif + return file; + } } + return NULL; +} +>>> + + + + + + + +\<header functions\><<< +static FILE* search_file_base( ARG_IV( const U_CHAR *, const U_CHAR *, const U_CHAR *, + struct env_var_rec *) ); +>>> + +\<functions\><<< +`[ +static FILE* search_file_base( name, dir, flags, env_dirs) + const U_CHAR *name`; + const U_CHAR *dir`; + const U_CHAR *flags`; + struct env_var_rec *env_dirs + +;{ U_CHAR *p; + FILE* file; + if( *dir == '~' ){ + while( TRUE ){ + p = abs_addr(dir, env_dirs? env_dirs->base : NULL); + file = search_file(name, p, flags); + free((void *) p); + if( file || !env_dirs ){ return file; } + env_dirs = env_dirs->next; + } + } else { + file = search_file(name, dir, flags); + } + return file; +} +>>> + + + +\<header functions\><<< +static char * abs_addr( ARG_II( const U_CHAR *, const U_CHAR *) ); +>>> + +\<functions\><<< +`[ +static char * abs_addr( dir, base) + const U_CHAR *dir`; + const U_CHAR *base + +;{ U_CHAR *p; + p = m_alloc(char, (int) strlen( dir ) + + (base? (int) strlen( base ):0) + + (int) strlen((char *) HOME_DIR ) + 1 ); + *p = '\0'; + if( (*(dir+1) == '~') && base ){ + if( *base == '~' ){ + (IGNORED) strct(p, HOME_DIR); + (IGNORED) strct(p, base+1); + } else { + (IGNORED) strct(p, base); + } + (IGNORED) strct(p, dir+2); + } else { + (IGNORED) strct(p, HOME_DIR); + (IGNORED) strct(p, dir+1); + } + return p; +} +>>> + + + +\SubSection{Search in Current Directory and Specified Directory} + + If a path specification ends in a '!', it's subdirectories are + searched too, else only the specified dir is searched. (This is the + way many TeX installations seem to do it, too). + + + +\<header functions\><<< +static FILE* search_file( ARG_III(const char *, const U_CHAR *, const U_CHAR *) ); +>>> + +\<functions\><<< +`[ +static FILE* search_file( name, dir, flags ) + const char *name`; + const U_CHAR *dir`; + const U_CHAR *flags + +;{ FILE* file; + U_CHAR str[256]; + int i; + BOOL subs; + `<search file in cur dir`> + (IGNORED) strcpy((char *) str, dir); + i = (int) strlen((char *) str) - 1; + subs = str[i] == '!'; + if( subs ) str[i] = '\0'; else i++; + `<cat / if needed`> + + `<search file in named dir`> + str[i] = '\0'; + return subs? search_file_ext( name, str, flags): + NULL; +} +>>> + +\<cat / if needed\><<< +(IGNORED) strct(str, +#if defined(__DJGPP__) + (( dir[i-1] == '/') || ( dir[i-1] == '\\')) + ? "" + : (is_forward_slash(dir)? "/" : "\\" ) +#else + (dir[i-1] == '/')? "" : "/" +#endif + ); +>>> + + + + + +\<search file in cur dir\><<< +if( (file = f_open(name, flags)) != NULL ){ + return file; } +>>> + +\<search file in named dir\><<< +(IGNORED) strct(str,name); +if( (file = f_open(str, flags)) != NULL ){ + str[i] = '\0'; add_to_cache(str,name,i); + return file; } +>>> + + + + +\<header functions\><<< +static void add_to_cache( ARG_III(const char*,const char*,int) ); +>>> + +\<functions\><<< +`[ +static void add_to_cache(dir,name,n) + const char* dir`; const char* name`; int n + +;{ + struct cache_font_rec *cur_cache_font; + + `<put dir in cache`> + `<store filename in cache`> +} +>>> + + + +\SubSection{Search in SubDirectories} + +\<header functions\><<< +static FILE* search_file_ext( ARG_III(const char *, const U_CHAR *, const U_CHAR *) ); +>>> + +\<functions\><<< +`[ +static FILE* search_file_ext( name, dir, flags ) + const char *name`; + const U_CHAR *dir`; + const U_CHAR *flags + +;{ U_CHAR str[256]; + FILE* file; + int n; + n = (int) strlen(dir); + (IGNORED) sprintf(str, +#if defined(__DJGPP__) + (( dir[n-1] == '/') || ( dir[n-1] == '\\')) + ? "%s%s" + : (is_forward_slash(dir)? "%s/%s" : "%s\\%s" ) +#else + (dir[n-1] == '/')? "%s%s" : "%s/%s" +#endif + , dir, name); + if( (file = f_open(str,flags)) != NULL ){ + add_to_cache(dir,name,n); + return file; + } + if( (str[n] == `<directory '/'`>) +#ifdef DOS_WIN32 + || (str[n] == '/' ) +#endif + ) n++; + str[n-1] = '\0'; +#ifndef NOSUBDIR +#ifdef WIN32 + `<file = search WIN32 subdir (name,str)`> +#else + `<file = search subdir (name,str)`> +#endif +#endif + return NULL; +} +>>> + + + + +Searches in subdirectories require opendir, closedir, readir. I can't +find them for dos, so I disabled them there. + +On Windows/dos, both forward slash (\''/') and backslash (\''\') are +used as path separator characters. In other environments, it is the +forward slash (\''/'). + +\<directory '/'\><<< +#if defined(__DJGPP__) + '\\' +#else + '/' +#endif +>>> + + + +\<defines\><<< +#if defined(__DJGPP__) +#define dir_path_slash(str) (is_forward_slash(str)? '/' : '\\') +#else +#define dir_path_slash(str) '/' +#endif +>>> + + + +\<header functions\><<< +#if defined(__DJGPP__) + static BOOL is_forward_slash( ARG_I(const char*) ); +#endif +>>> + +\<functions\><<< +#if defined(__DJGPP__) +`[ +static BOOL is_forward_slash(str) + const char* str +;{ + while( *str ){ if( *(str++) == '/' ) { return TRUE; } } + return FALSE; +} +#endif +>>> + + + +\<file = search subdir (name,str)\><<< +{ DIR *dp; + `<struct dirent`> *dirp; + struct STSTAT buf; + if( (dp = opendir( str )) != NULL ){ + while( (dirp = readdir(dp)) != NULL ){ + if( !eq_str(dirp->d_name, ".") && + !eq_str(dirp->d_name, "..") ) + { `<reach into the subdirectory`> + } } + (void) closedir(dp); +} } +>>> + + +\<reach into the subdirectory\><<< +(IGNORED) strcpy((char *) str+n, (char *) dirp->d_name ); +str[n-1] = dir_path_slash(str); +if( LSTAT(str, &buf) >= 0 ) + if( S_ISDIR( buf.st_mode ) ) + if( (file = search_file_ext(name, str, flags)) != NULL ){ + (void) closedir(dp); + return file; } +>>> + +\<h-include\><<< +#ifdef DOS_WIN32 +#include <io.h> +#endif +>>> + + + + + +\<defines\><<< +#ifndef S_ISDIR +#define S_ISDIR(M) (((M) & _S_IFMT)==_S_IFDIR) `% test for directory `% +#endif + +#ifndef _S_IFDIR +#define _S_IFDIR S_IFDIR +#endif + +#ifndef _S_IFMT +#define _S_IFMT S_IFMT +#endif +>>> + + +`lstat' returns info about the symbolic link, not the file referenced by the +symbolic link as `stat' does + +STSTAT is for `struct stat', LSTAT is for the function. + Don't define STAT, aix's {\tt <sys/dir.h>} defines it as 1 +(Peter Breitenlohner). + +\Verbatim +1998-10-22 Eli Zaretskii <eliz@is.elta.co.il> DJGPP: + (LSTAT): Define to stat for every system that doesn't define + S_ISLNK. +\EndVerbatim + + + +\<defines\><<< +#if defined(DOS_WIN32) || !defined(S_ISLNK) +#define LSTAT stat +#else +#define LSTAT lstat +#endif +#define STSTAT stat +>>> + + + +\<h-include\><<< +#include <sys/stat.h> +`% stat _IF_DIR +`% +>>> + +\SubSection{dirent} + + readdir, opendir, closedir + + +\<h-defines DOS-WIN32\><<< +#ifdef DOS_WIN32 +#define STRUCT_DIRENT +#endif +>>> + + +\<h-include\><<< +#ifdef HAVE_DIRENT_H +`<needs dirent.h`> +#else +#ifndef STRUCT_DIRENT +#define STRUCT_DIRECT +#endif +`<needs simulated dirent.h`> +#endif +>>> + + + + + +\<needs dirent.h\><<< +#include <dirent.h> +>>> + + +\<needs simulated dirent.h\><<< +#ifdef HAVE_SYS_NDIR_H +#include <sys/ndir.h> +#endif +#ifdef HAVE_SYS_DIR_H +#include <sys/dir.h> +#endif +#ifdef HAVE_NDIR_H +#include <ndir.h> +#endif +>>> + + + + +\<struct dirent\><<< + +#ifdef STRUCT_DIRECT + struct direct +#else + struct dirent +#endif +>>> + + +\ifHtml[\HPage{more}\Verbatim + + I updated all of + + ftp://www.tug.org/private/texk7.2drivers/ + +A small patch for tex4htk. It won't compile on systems without +<dirent.h>, therefore I copied this from gsftopk. I don't know how to +handle the MSVC_1_52_DOS correctly. + + + + + +--- tex4ht.c.ORIG Wed Mar 18 11:07:26 1998 ++++ tex4ht.c Wed Mar 18 11:17:39 1998 +@@ -146,7 +146,21 @@ + + + #ifndef MSVC_1_52_DOS +-#include <dirent.h> ++#ifdef HAVE_DIRENT_H ++#include <dirent.h> ++typedef struct dirent struct_dirent; ++#else /* no <dirent.h> */ ++typedef struct direct struct_dirent; ++#ifdef HAVE_SYS_NDIR_H ++#include <sys/ndir.h> ++#endif ++#ifdef HAVE_SYS_DIR_H ++#include <sys/dir.h> ++#endif ++#ifdef HAVE_NDIR_H ++#include <ndir.h> ++#endif ++#endif /* no <dirent.h> */ + + #endif + +@@ -2598,7 +2612,7 @@ + #ifndef NOSUBDIR + + { DIR *dp; +- struct dirent *dirp; ++ struct_dirent *dirp; + struct STSTAT buf; + if( (dp = opendir( str )) != NULL ){ + while( (dirp = readdir(dp)) != NULL ){ + +\EndVerbatim\EndHPage{}]\fi + + + + + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\SubSection{Try to Open Path-Named File} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\<header functions\><<< +static FILE* f_open_pathed_filename( ARG_II(const char*,const char*) ); +>>> + +\<functions\><<< +`[ +static FILE* f_open_pathed_filename( name, flags ) + const char* name `; + const char* flags +;{ FILE* file; + U_CHAR *str; + file = NULL; + if( *name == '~' ){ + if( HOME_DIR ){ + str = m_alloc(char, strlen((char *) HOME_DIR)+strlen(name)); + (IGNORED) sprintf(str,"%s%s", HOME_DIR, name+1); + file = f_open(str,flags); + free((void *) str); + } + } else { file = f_open( name, flags ); } + return file; +} +>>> + + +%%%%%%%%%%%%%%%%%%%%%%% +\Chapter{Unicode into Character Encoding} +%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Put Character} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<header functions\><<< +static INTEGER put_4ht_ch( ARG_II(int,FILE *) ); +>>> + +\<functions\><<< +`[ +static INTEGER put_4ht_ch(ch,htFile) int ch `; FILE* htFile +;{ + int c; + c = ch; + if( ch=='&' ){ + `<flush incomplete unicode`> + if( put_4ht_off ){ + c = putc( ch, htFile ); + } else { + uni_code[0] = '&'; + uni_code_p = 1; + put_4ht_file = htFile; + } + } else + if( uni_code_p ){ + if( ch == ';' ){ `<process unicode`> uni_code_p = 0; } + else if ( ((uni_code_p+1) == MAX_UNI_CODE) + || + ( ((ch<'0') || (ch>'9')) + && ((ch<'a') || (ch>'f')) + && ((ch<'A') || (ch>'F')) + && (ch!='#') + && (ch!='x') + && (ch!='X') + ) + ) + { `<flush incomplete unicode`> + c = putc( ch, htFile ); + } else { uni_code[ uni_code_p++ ] = ch; } + } else { c = putc( ch, htFile ); } + return c; +} +>>> + +\<vars\><<< +static FILE* put_4ht_file = (FILE *) 0; +static int put_4ht_off = 1; +static char uni_code[MAX_UNI_CODE]; +static short uni_code_p = 0; +>>> + +\<defines\><<< +#define MAX_UNI_CODE 20 +>>> + + +\<on/off unicode\><<< +special_n--; +switch ( code = get_char() ){ + case '+': { put_4ht_off++; `<flush incomplete unicode`> break; } + case '-': { if( put_4ht_off>0 ){ put_4ht_off--; } + else { warn_i_str(52, "@u-"); } + break; } +} +>>> + + +%%%%%%%%%%%%% +\Section{Flash Unrecognized Codes} +%%%%%%%%%%%%% + + + + +\<flush incomplete unicode\><<< +flush_uni(); +>>> + +\<header functions\><<< +static void flush_uni( ARG_I(void) ); +>>> + +\<functions\><<< +static void flush_uni( MYVOID ) +{ + int i; + for( i=0; i<uni_code_p; i++ ){ + (IGNORED) putc( uni_code[i], put_4ht_file ); + } + uni_code_p = 0; + put_4ht_file = (FILE *) 0; +} +>>> + + + + + +%%%%%%%%%%%%% +\Section{Load unicode.4hf Table} +%%%%%%%%%%%%% + + +\<load unicode.4hf\><<< +{ U_CHAR name[256]; + FILE* file; + (IGNORED) sprintf(name, "%s.4hf", "unicode"); + `<search file in htf locations`> + if( file ){ + `<unicode.4hf vars`> + `<mem for charset`> + `<read unicode.4hf`> + put_4ht_off = 0; + } else{ put_4ht_off = 1; `<no mem for charset`> } +} +>>> + + +\<unicode.4hf vars\><<< +int chr, delimiter, delimiter_n, line_no, digit, i, j; +U_CHAR in[512], *in_p, * start[4], *p; +BOOL char_on, err; +int value; +>>> + + +\<read unicode.4hf\><<< +err = FALSE; +line_no = 0; +while( TRUE ){ + line_no++; + chr = (int) getc(file); + if( chr == EOF ){ break; } + if( (chr>32) && (chr<127) ){ + `<scan 4hf fields`> + if( delimiter_n == 8 ){ + if( *in != '?' ) { + if( `<not hexa unicode?`> ){ err = TRUE; } + else { + `<value = hex into int`> + if( start[3] == (in_p-1) ){ + if( !err ){ `<store type-less 4hf endtry`> } + } else { `<store typed 4hf endtry`> } + } } } + else { err = TRUE; } + `<error 4hf fields`> + } + while( (chr != EOF) && (chr!='\n') ){ + chr = (int) getc(file); + } + if( chr == EOF ){ break; } +} +>>> + + +\<not hexa unicode?\><<< + (*in != '&') +|| (*(in+1) != '#') +|| ( (*(in+2) != 'x') && (*(in+2) != 'X')) +|| (*(start[1] - 2) != ';') +>>> + +\<scan 4hf fields\><<< +delimiter = chr; +delimiter_n = 1; +char_on = TRUE; +in_p = in; +while( TRUE ) { + chr = (int) getc(file); + if( (chr == EOF) || (chr=='\n') ){ break; } + if( chr == delimiter ){ + if( char_on ){ *(in_p++) = '\0'; } + else{ start[ delimiter_n/2 ] = in_p; } + char_on = !char_on; + delimiter_n++; + } else if (char_on ) { + *(in_p++) = chr; + } + if( delimiter_n==8 ){ break; } +} +>>> + +\<process 4hf fields\><<< + +>>> + + + +\<error 4hf fields\><<< +if( err ){ + warn_i_int(48,line_no); + (IGNORED) printf( "%c", delimiter ); + for( p=in; p != in_p; p++ ){ + if( *p=='\0' ){ + (IGNORED) printf("%c", delimiter); + if( p != in_p-1 ){ (IGNORED) printf(" %c", delimiter); } + } + else { (IGNORED) printf( "%c", *p ); } + } + (IGNORED) printf( "\n" ); + err = FALSE; +} +>>> + + +%%%%%%%%%%%%% +\Section{Store Entry of Table} +%%%%%%%%%%%%% + + +\<types\><<< +struct charset_rec{ int ch; + char* str; }; +>>> + +\<vars\><<< +static int charset_n = 0, max_charset_n; +static struct charset_rec *charset; +>>> + + +\<mem for charset\><<< +max_charset_n = 256; +charset = m_alloc(struct charset_rec, 256); +>>> + +\<no mem for charset\><<< +max_charset_n = 0; +>>> + + +\<value = hex into int\><<< +value = 0; +for( p=in+3; *p!=';'; p++){ + digit = (int) *p; + if( (digit>='0') && (digit<='9') ){ digit -= '0'; } + else if( (digit>='A') && (digit<='F') ){ digit -= BASE_A; } + else if( (digit>='a') && (digit<='f') ){ digit -= BASE_a; } + else { digit=0; err = TRUE; } + value = 16*value + digit; +} +>>> + + +\<defines\><<< +#define BASE_A 55 +#define BASE_a 87 +>>> + + +\<store type-less 4hf endtry\><<< +`<mem for new 4ht entry`> +p = m_alloc(char, (int) (start[3] - start[2]) ); +(IGNORED) strcpy((char *) p, (char *) start[2] ); +i = charset_n; +while( i-- > 0 ){ + if( charset[i].ch == value ){ + free((void *) charset[i].str); + break; + } else { + if( (charset[i].ch < value) + || ((charset[i].ch > value) && (i==0)) ){ + if( charset[i].ch < value ){ i++; } + charset_n++; + for( j=charset_n; j>i; j-- ){ + charset[j].ch = charset[j-1].ch; + charset[j].str = charset[j-1].str; + } + break; + } } +} +if(i == -1){ i = charset_n; } +if( i==charset_n ){ charset_n++; } +charset[i].str = p; +charset[i].ch = value; +>>> + +The above backward search allows sorted files to be loaded in linear time. + + +\<mem for new 4ht entry\><<< +if( (charset_n+1) == max_charset_n){ + max_charset_n += 10; + charset = (struct charset_rec *) r_alloc((void *) charset, + (size_t) ((max_charset_n) * sizeof(struct charset_rec) )); +} +>>> + + + + +%%%%%%%%%%%%% +\Section{Use Unicode Substitution} +%%%%%%%%%%%%% + + + +\<process unicode\><<< +if( uni_code[1] != '#' ){ + `<flush incomplete unicode`> + (IGNORED) putc( ch, htFile ); +} +else{ + int i, base, value, digit; + if( (uni_code[2] == 'x') || (uni_code[2] == 'X') ){ + base =16; i=3; + } else { base=10; i=2; } + value = 0; + for( ; i<uni_code_p; i++ ){ + digit = uni_code[i]; + if( (digit>='0') && (digit<='9') ){ digit -= '0'; } + else if( (digit>='A') && (digit<='F') ){ digit -= BASE_A; } + else if( (digit>='a') && (digit<='f') ){ digit -= BASE_a; } + else { value = -1; break; } + if( digit >= base ){ value=-1; break; } + value = value*base + digit; + } + if( value<0 ){ `<flush incomplete unicode`> + (IGNORED) putc( ch, htFile ); + } else { + `<search 4hf table`> +} } +>>> + +\<search 4hf table\><<< + int bottom, mid, top; + BOOL found=FALSE; +bottom = 0; top = charset_n; +while( !found ){ + mid = (bottom + top) / 2; + if( value == charset[mid].ch ){ + `<put 4hf replacement`> + found = TRUE; + } else if( value < charset[mid].ch ){ + if( bottom == top ){ break; } + top = mid; + } + else { + if ( bottom < mid ){ bottom = mid; } + else if ( bottom<top ){ bottom++; } + else{ break; } + } +} +if( ! found ){ + if( u10 || utf8 ){ `<hex uni to base 10 or utf8`> } + `<flush incomplete unicode`> + if( !utf8 ){ (IGNORED) putc( ch, htFile ); } +} +>>> + +\<put 4hf replacement\><<< +{ U_CHAR *p; + p = charset[mid].str; + while( *p != '\0' ){ + if( *p=='\\' ){ + p++; + if( *p=='\\' ){ + (IGNORED) putc( '\\', htFile ); + } else { + int i; + i = *p - '0'; + while( *(++p) != '\\' ){ i = 10*i + *p - '0'; } + (IGNORED) putc( i, htFile ); + } } + else { + (IGNORED) putc( *p, htFile ); + if ( (*p=='&') && u10 ){ `<u10 for 4hf replacement`> } + } + p++; +} } +>>> + +The utf8 option don't apply for unicode symbols coming from a 4hf fonts. + + +%%%%%%%%%%%%% +\Section{Base 10 for Entity Codes} +%%%%%%%%%%%%% + + + + + +\<vars\><<< +static BOOL u10 = FALSE; +>>> + +\<get unicode entity representations\><<< +if( eq_str(p+2, "10") ){ u10 = TRUE; } +`<else get utf8 unicode encoding`> +else{ bad_arg;} +>>> + +\<hex uni to base 10 or utf8\><<< + short n; + long dec; + int ch; + char uni_10[MAX_UNI_CODE]; +if( (uni_code[2] == 'x') || (uni_code[2] == 'X') ) { + dec = 0; + for( n=3; n<uni_code_p; n++ ){ + ch = uni_code[n]; + dec = 16*dec + + ((ch > '9')? + ( 10 + ((ch > 'Z')? (ch-'a') : (ch-'A')) ) + : (ch-'0')); + } + if( u10 ){ `<dec to u10`> } + else { `<uni in utf8`> } +} +>>> + + +\<dec to u10\><<< + if( dec == 0 ){ + uni_code_p = 3; uni_code[2] = '0'; + } else { + n = 0; + while( dec > 0 ){ uni_10[ n++ ] = dec % 10 + '0'; dec /= 10; } + uni_code_p = 2; + while( n>0 ){ uni_code[ uni_code_p++ ] = uni_10[ --n ]; } + } +>>> + +\<u10 for 4hf replacement\><<< +if ( *(p+1) == '#' ){ + p++; + (IGNORED) putc( '#', htFile ); + if ( (*(p+1) == 'x') || (*(p+1) == 'X') ){ + int value, digit; + U_CHAR *q; + q = p+2; + value = 0; + digit = *(q++); + while( digit!=0 ){ + if( (digit>='0') && (digit<='9') ){ + value = value*16 + digit - '0'; + } + else if( (digit>='A') && (digit<='F') ){ + value = value*16 + digit - 'A'+10; + } + else if( (digit>='a') && (digit<='f') ){ + value = value*16 + digit - 'a'+10; } + else { + if( digit == ';' ){ + `<display value in u10`> + p=q-2; + } + break; + } + digit = *(q++); + } +} } +>>> + +\<display value in u10\><<< + char uni_10[MAX_UNI_CODE]; + int n; +n = 0; +while( value>0 ){ + uni_10[ n++ ] = value % 10 + '0'; + value /= 10; +} +while( n>0 ){ + (IGNORED) putc( uni_10[--n], htFile ); +} +>>> + + + +%%%%%%%%%%%%% +\Section{UTF-8 for Entity Codes} +%%%%%%%%%%%%% + +\Verbatim +U-00000000 - U-0000007F: 0xxxxxxx +U-00000080 - U-000007FF: 110xxxxx 10xxxxxx +U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx +U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx +U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx +U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx +\EndVerbatim + + +\<dec to utf8\><<< +if( dec < 0x80 ){ + uni_code_p = 1; uni_code[0] = dec; +} +else if( dec < 0x800 ){ + uni_code_p = 2; + uni_code[0] = (dec >> 6) | 0xC0; + uni_code[1] = (dec & 0x3F) | 0x80; +} +else if( dec < 0x10000 ){ + uni_code_p = 3; + uni_code[0] = (dec >> 12) | 0xE0; + uni_code[1] = ((dec >> 6) & 0x3F) | 0x80; + uni_code[2] = (dec & 0x3F) | 0x80; +} +else if( dec < 0x200000 ){ + uni_code_p = 4; + uni_code[0] = (dec >> 18) | 0xF0; + uni_code[1] = ((dec >> 12) & 0x3F) | 0x80; + uni_code[2] = ((dec >> 6) & 0x3F) | 0x80; + uni_code[3] = (dec & 0x3F) | 0x80; +} +else if( dec < 0x4000000 ){ + uni_code_p = 5; + uni_code[0] = (dec >> 24) | 0xF8; + uni_code[1] = ((dec >> 18) & 0x3F) | 0x80; + uni_code[2] = ((dec >> 12) & 0x3F) | 0x80; + uni_code[3] = ((dec >> 6) & 0x3F) | 0x80; + uni_code[4] = (dec & 0x3F) | 0x80; +} +else if( dec <= 0x7FFFFFFF ){ + uni_code_p = 6; + uni_code[0] = (dec >> 30) | 0xFC; + uni_code[1] = ((dec >> 24) & 0x3F) | 0x80; + uni_code[2] = ((dec >> 18) & 0x3F) | 0x80; + uni_code[3] = ((dec >> 12) & 0x3F) | 0x80; + uni_code[4] = ((dec >> 6) & 0x3F) | 0x80; + uni_code[5] = (dec & 0x3F) | 0x80; +} +>>> + + +\<vars\><<< +static BOOL utf8 = FALSE; +>>> + +\<else get utf8 unicode encoding\><<< +else if( eq_str(p+2, "tf8") ){ utf8 = TRUE; } +>>> + +\<uni in utf8\><<< +`<dec to utf8`> +else { + n = 0; + while( dec > 0 ){ uni_10[ n++ ] = dec % 10 + '0'; dec /= 10; } + uni_code_p = 2; + while( n>0 ){ uni_code[ uni_code_p++ ] = uni_10[ --n ]; } +} +>>> + + +%%%%%%%%%%%%% +\Section{Replacements for HTF} +%%%%%%%%%%%%% + +\<store typed 4hf endtry\><<< +`<mem for new htf-4hf entry`> +(IGNORED) strcpy((char *) p, (char *) start[2] ); +i = htf_4hf_n; +while( i-- > 0 ){ + if( htf_4hf[i].ch == value ){ + free((void *) htf_4hf[i].str); + break; + } else { + if( (htf_4hf[i].ch < value) + || ((htf_4hf[i].ch > value) && (i==0)) ){ + if( htf_4hf[i].ch < value ){ i++; } + htf_4hf_n++; + for( j=htf_4hf_n; j>i; j-- ){ + htf_4hf[j].ch = htf_4hf[j-1].ch; + htf_4hf[j].str = htf_4hf[j-1].str; + htf_4hf[j].type1 = htf_4hf[j-1].type1; + htf_4hf[j].type2 = htf_4hf[j-1].type2; + } + break; +} } } +if(i == -1){ i = htf_4hf_n; } +if(i == htf_4hf_n){ htf_4hf_n++; } +htf_4hf[i].str = p; +htf_4hf[i].ch = value; +`<htf_4hf[i].type1 = ...`> +`<htf_4hf[i].type2 = ...`> +>>> + + +\<end loading fonts\><<< +for( i = 0; i<htf_4hf_n; i++){ + free((void *) htf_4hf[i].str); +} +free((void *) htf_4hf); +>>> + + + + +\<mem for new htf-4hf entry\><<< +if( (htf_4hf_n+1) == max_htf_4hf_n){ + max_htf_4hf_n += 10; + htf_4hf = (struct htf_4hf_rec *) r_alloc((void *) htf_4hf, + (size_t) ((max_htf_4hf_n) * sizeof(struct htf_4hf_rec) )); +} +p = m_alloc(char, (int) (start[3] - start[2]) ); +>>> + + +\<htf_4hf[i].type1 = ...\><<< +value = 0; +p = start[1]; +while( *p != '\0' ){ + if( (*p < '0') || (*p > '9') ) break; + value = value * 10 + *p - '0'; + p++; +} +htf_4hf[i].type1 = value; +>>> + +\<htf_4hf[i].type1 = ...\><<< +value = 0; +p = start[3]; +while( *p != '\0' ){ + if( (*p < '0') || (*p > '9') ) break; + value = value * 10 + *p - '0'; + p++; +} +htf_4hf[i].type2 = value; +>>> + + +\<types\><<< +struct htf_4hf_rec { int ch, type1, type2; + char* str; }; +>>> + +\<vars\><<< +static int htf_4hf_n = 0, max_htf_4hf_n; +static struct htf_4hf_rec *htf_4hf; +>>> + + +\<mem for charset\><<< +max_htf_4hf_n = 256; +htf_4hf = m_alloc(struct htf_4hf_rec, 256); +>>> + +\<no mem for charset\><<< +max_htf_4hf_n = 0; +>>> + + + +%%%%%%%%%%%%% +\Section{Propagate Changes into the HTF Fonts} +%%%%%%%%%%%%% + +\<propagate 4hf info into htf\><<< +if( + (*str == '&') + && (*(str+1) == '#') + && ( (*(str+2) == 'x') || (*(str+2) == 'X')) + && (*(str + strlen((char *) str) - 1) == ';') +) { + char* p; + int value = 0; + BOOL err = FALSE; + for( p=str+3; *p!=';'; p++){ + int digit = (int) *p; + if( (digit>='0') && (digit<='9') ){ digit -= '0'; } + else if( (digit>='A') && (digit<='F') ){ digit -= BASE_A; } + else if( (digit>='a') && (digit<='f') ){ digit -= BASE_a; } + else { digit=0; err = TRUE; } + value = 16*value + digit; + } + if( !err ){ + `<search 4hf replacement in htf-4hf`> + `<search 4hf replacement in charset`> +} } +>>> + +\<htf replacement from htf-4hf\><<< +if( htf_4hf[mid].type1 == ch1 ){ + ch1 = htf_4hf[mid].type2; + (IGNORED) strcpy((char *) str, (char *) htf_4hf[mid].str ); +} +>>> + +\<htf replacement from charset\><<< +if( charset[mid].type1 == ch1 ){ + ch1 = charset[mid].type2; + (IGNORED) strcpy((char *) str, (char *) charset.str ); +} +>>> + +\<search 4hf replacement in htf-4hf\><<< + int bottom, mid, top; + BOOL found=FALSE; +bottom = 0; top = htf_4hf_n; +while( !found ){ + mid = (bottom + top) / 2; + if( value == htf_4hf[mid].ch ){ + `<htf replacement from htf-4hf`> + found = TRUE; + } else if( value < htf_4hf[mid].ch ){ + if( bottom == top ){ break; } + top = mid; + } + else { + if ( bottom < mid ){ bottom = mid; } + else if ( bottom<top ){ bottom++; } + else{ break; } + } +} +>>> + + + +\<htf replacement from charset\><<< +bottom = 0; top = charset_n; +while( !found ){ + mid = (bottom + top) / 2; + if( value == charset[mid].ch ){ + `<htf into 4hf`> + found = TRUE; + } else if( value < charset[mid].ch ){ + if( bottom == top ){ break; } + top = mid; + } + else { + if ( bottom < mid ){ bottom = mid; } + else if ( bottom<top ){ bottom++; } + else{ break; } + } +} +>>> + + +%%%%%%%%%%%%%%%%%%%%%%% +\Chapter{Utilities} +%%%%%%%%%%%%%%%%%%%%%%%% + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Output Character} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + +\<header functions\><<< +static INTEGER insert_ch( ARG_I(int) ); +>>> + +\<functions\><<< +`[ +static INTEGER insert_ch(ch) int ch +;{ + if( !ignore_chs ){ + BOOL flag; + `<flag = empty next-str?`> + if( !flag ){ + try_new_line(); + `<insert ch to text`> + text_on = TRUE; + } } + `<return char width`> +} +>>> + + + + + /* if (ch < 0) ch+=256; /*NEW */ + + +\<flag = empty next-str?\><<< +flag = FALSE; +if( `<next-str`> ) { + if( eq_str(next_str, "") ) { + flag = TRUE; + free((void *) next_str); + next_str = (char *) 0; +} } +>>> + + + +\<header functions\><<< +static void put_char( ARG_I(int) ); +>>> + +\<functions\><<< +`[ +static void put_char( ch ) int ch +;{ + if( !ignore_chs + && !( ((ch==' ') || (ch=='\n')) && no_root_file ) + ){ + `<open output file`> + if( ch_map_flag ){ + if( special_on || ((ch != '\n') && (ch != ' ')) ){ + `<insert ch to ch-map`> } + }else { + if ( ch == '\n' ){ `<insert eoln ch`> } + else if ( ch == ' ' ){ `<insert space ch`> } + else { (IGNORED) put_4ht_ch( ch, cur_o_file ); } +} } } +>>> + +\<vars\><<< +static BOOL special_on = FALSE; +>>> + + + +%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Output String} +%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<header functions\><<< +static void print_f( ARG_I(const char*) ); +>>> + +\<functions\><<< +`[ +static void print_f(str) const char* str +;{ + `<open output file`> + if( ch_map_flag ){ + while( *str ){ put_char( *str ); str++; } + }else { + (IGNORED) print_f_4ht( str ); +} } +>>> + +% fprintf(cur_o_file, "%s", str); + + + +\<header functions\><<< +static void print_f_4ht( ARG_I(const char*) ); +>>> + +\<functions\><<< +`[ +static void print_f_4ht(str) const char* str +;{ + `<open output file`> + if( ch_map_flag ){ + while( *str ){ put_char( *str ); str++; } + } else { + while( *str ){ + (IGNORED) put_4ht_ch( *str, cur_o_file ); + str++; +} } } +>>> + + + + +%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Read Character} +%%%%%%%%%%%%%%%%%%%%%%%%% + +\<header functions\><<< +static int get_char( ARG_I(void) ); +>>> + +\<functions\><<< +static int get_char(MYVOID) +{ + return (int) getc(dvi_file); +} +>>> + + +\<header functions\><<< +static int get_noop( ARG_I(void) ); +>>> + +\<functions\><<< +static int get_noop(MYVOID) +{ int ch; + while( (ch = get_char()) == `<no op`> ){;} + return ch; +} +>>> + + + +\Section{Read Strings} + +\<header functions\><<< +static char* get_str( ARG_I(int) ); +>>> + +\<functions\><<< +`[ +static char* get_str(n) int n +;{ U_CHAR *q, *p; + p = q = m_alloc(char,n+1); + while( n-- ) *q++ = get_char(); + *q = '\0'; + return p; +} +>>> + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Read Unsigned Integer} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\<defines\><<< +#define get_unt(n) fget_unt(dvi_file,n) +>>> + +\<header functions\><<< +static long fget_unt( ARG_II(FILE*, int) ); +>>> + +\<functions\><<< +`[ +static long fget_unt( file, n ) + FILE* file`; + register int n + +;{ register long val = 0; + while( n-- ){ val = (val << 8) + (unsigned INTEGER) getc(file) ; } + return val; +} +>>> + +\Section{Read Signed Integer} + + + +\<defines\><<< +#define get_int(n) fget_int(dvi_file,n) +>>> + +\<header functions\><<< +static long fget_int( ARG_II(FILE *, int) ); +>>> + +\<functions\><<< +`[ +static long fget_int( file, n ) + FILE *file`; + int n + +;{ register long val; + val = (unsigned INTEGER) getc(file); + if( val & 0x80 ) val -= 0x100; + while( --n ){ val = (val << 8) + (unsigned INTEGER) getc(file); } + return val; +} +>>> + +The implementation in dvi2ps takes the following form with the comment +``This code assumes that the right-shift is an arithmetic, rather than +logical, shift which will propagate the sign bit right. According to +Kernighan and Ritchie, this is compiler dependent!''. + + +\Verbatim +val = getc(fp); +n1 = n--; +while (n--) { val <<= 8; + val |= getc(fp); } +val<<=32-8*n1; +val>>=32-8*n1; /* sign extend */ +\EndVerbatim + + + + +\<header functions\><<< +static long cond_int( ARG_I(register INTEGER) ); +>>> + +\<functions\><<< +`[ +static long cond_int( n ) + register INTEGER n +;{ register long val; + int ch; + val = (unsigned int) (ch = get_char()); + cond_idv_char( ch ); + if( val & 0x80 ) val -= 0x100; + while( --n ){ + val = (val << 8) + (unsigned int) (ch = get_char()); + cond_idv_char( ch ); + } + return val; +} +>>> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Strings Equality} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\<defines\><<< +#define eq_str(x,y) (!strcmp(x,y)) +#define gt_str(x,y) (strcmp(x,y)>0) +>>> + + + + + + +\Section{Warnings and Errors} + + +\SubSection{Messages} + +\<warn and err messages\><<< +`<command line options`>, `%0`% +"Can't find/open file ``%s'\n", `%1`% +"Can't open output file for ``%s'\n", `%2`% +"Can't close file ``%s' (file is not open)\n", `%3`% +"Insufficient memory\n", `%4`% +"Bad character code: %d\n", `%5`% +"Can't find font number %d\n", `%6`% +"Improper dvi file\n", `%7`% +"Improper op while scanning font defs in postamble\n",`%8`% +"Problem with command line\n", `%9`% +"Font definition repeated in postamble\n", `%10`% +"Empty entry in font environment variable\n", `%11`% +"Can't access directory ``%s\n'", `%12`% +"Too many directories in font environment variable\n",`%13`% +"Missing fonts, can't proceed\n", `%14`% +"Invalid header in file ``%s'\n", `%15`% +"Checksum inconsistent\n", `%16`% +"MAXFONTS too small: %d\n", `%17`% +"Improper signature at end of file ``%s.htf'\n", `%18`% +"Improper signature at start of file ``%s.htf'\n", `%19`% +"Improper file ``%s.htf'\n", `%20`% +"Couldn't find font ``%s.htf' (char codes: ", `%21`% +"File ``%s.htf' starts/ends with character code %d (instead of %d)\n",`%22`% +"Implementation problem\n", `%23`% +"Improper groups in \\special{t4ht+}... idv[%d]\n", `%24`% +"Too many characters (> %d) for map line: ``%c'\n", `%25`% +"Extra characters in \\special{t4ht%c...", `%26`% +"Page break within a ch map/picture\n", `%27`% +"Char code >255 in htf file: %d\n", `%28`% +"Improper char for code in htf file: %c\n", `%29`% +`<signals messages: 30-32`> `%30-32`% +#ifdef DOS_WIN32 +"%c-script too long in tex4ht.env \n", `%33`% +#else +"%c-script too long in tex4ht.env (.tex4ht)\n", `%33`% +#endif +"Too many rows (> %d) for map: ``%c'\n", `%34`% +"More than 256 strings in font\n", `%35`% +"\\special{t4ht;%c...}?\n", `%36`% +"\\special{t4ht;|%s}?\n", `%37`% +"\\special{t4ht~!%s}?\n", `%38`% +"\\special{t4ht\"...%s}?\n", `%39`% +"System error 40\n", `%40`% +"``%c' in \\special{t4ht@...} or \\special{t4ht@-...}?\n", `%41`% +"\\special{t4ht~...} without \\special{t4ht~}\n", `%42`% +"Ignoring \\special{t4ht.%s}\n", `%43`% +"PUSH for \\special{t4ht<...%s}?\n", `%44`% +"Bad character code (%d) in \\special{t4h~}...\n", `%45`% +"Page break in \\special{t4h~}...\n", `%46`% +"tex4ht.fls: Couldn't find file ``%s'\n", `%47`% +"Improper entry (line %d)\n", `%48`% +"Improper environment variable %s: ``%s'\n", `%49`% +"Missing %s\n", `%50`% +"Can't back from file ``%s\n'", `%51`% +"\\special{t4ht%s}?\n", `%52`% +"Improper -v option\n", `%53`% +>>> + +\<vars\><<< +static const U_CHAR *warn_err_mssg[]={ `<warn and err messages`> "" }; +>>> + + +\SubSection{Warnings Commands} + +\<header functions\><<< +static void warn_i( ARG_I(int) ); +>>> + +\<functions\><<< +`[ +static void warn_i(n) int n +;{ (IGNORED) fprintf(stderr,"--- warning --- "); + (IGNORED) fprintf(stderr, "%s", warn_err_mssg[n]); + show_err_context(); +} +>>> + +\<warning(22\><<< +(IGNORED) fprintf(stderr,"--- warning --- "); +(IGNORED) fprintf(stderr, warn_err_mssg[22] +>>> + +% \<vars\><<< +% static U_CHAR warning[] = "--- warning --- "; +% >>> + + + +\<header functions\><<< +static void warn_i_int( ARG_II(int,int) ); +>>> + +\<functions\><<< +`[ +static void warn_i_int(n,i) int n`; int i + +;{ (IGNORED) fprintf(stderr,"--- warning --- "); + (IGNORED) fprintf(stderr, warn_err_mssg[n], i); + show_err_context(); +} +>>> + + + +\<header functions\><<< +static void warn_i_int_2( ARG_III(int,int,int) ); +>>> + +\<functions\><<< +`[ +static void warn_i_int_2(n,i,j) int n`; int i`; int j + +;{ (IGNORED) fprintf(stderr,"--- warning --- "); + (IGNORED) fprintf(stderr, warn_err_mssg[n], i, j); + show_err_context(); +} +>>> + + + +\<header functions\><<< +static void warn_i_str( ARG_II(int,const char *) ); +>>> + +\<functions\><<< +`[ +static void warn_i_str(n,str) + int n`; + const char *str + +;{ + (IGNORED) fprintf(stderr,"--- warning --- "); + (IGNORED) fprintf(stderr,warn_err_mssg[n], str); + show_err_context(); +} +>>> + + + + +\<header functions\><<< +static void warn_i_str2( ARG_III(int,const char *,const char *) ); +>>> + +\<functions\><<< +`[ +static void warn_i_str2(n,str1,str2) + int n`; + const char *str1`; + const char *str2 + +;{ (IGNORED) fprintf(stderr,"--- warning --- "); + (IGNORED) fprintf(stderr,warn_err_mssg[n], str1,str2); + show_err_context(); +} +>>> + + +\SubSection{Error Commands} + + + + +\<defines\><<< +#define bad_arg err_i(0) +#define bad_in_file(name) err_i_str(1,name) +#define bad_out_file(name) err_i_str(2,name) +#define bad_special(name) warn_i_str(3,name) +#define bad_mem err_i(4) +#define bad_char(chr) warn_i_int(5,chr) +#define bad_dvi err_i(7) +>>> + + +\<header functions\><<< +static void err_i( ARG_I(int) ); +>>> + +\<functions\><<< +`[ +static void err_i(n) int n + +;{ (IGNORED) fprintf(stderr,"--- error --- "); + (IGNORED) fprintf(stderr, "%s", warn_err_mssg[n]); + show_err_context(); + exit(EXIT_FAILURE); +} +>>> + +REPLACE EXIT with somthing that DOS also accept. + +\<header functions\><<< +static void err_i_int( ARG_II(int,int) ); +>>> + +\<functions\><<< +`[ +static void err_i_int(n,i) int n`; int i + +;{ (IGNORED) fprintf(stderr,"--- error --- "); + (IGNORED) fprintf(stderr, warn_err_mssg[n], i); + show_err_context(); + exit(EXIT_FAILURE); +} +>>> + + +\<header functions\><<< +static void err_i_str( ARG_II(int,char *) ); +>>> + +\<functions\><<< +`[ +static void err_i_str(n,str) + int n`; + U_CHAR *str + +;{ (IGNORED) fprintf(stderr,"--- error --- "); + (IGNORED) fprintf(stderr, warn_err_mssg[n], str); + show_err_context(); + exit(EXIT_FAILURE); +} +>>> + +\SubSection{Extra Characters in Special} + + + + +\<check for extra special chars\><<< +if( special_n > 0 ){ + warn_i_int( 26, sv); + while( special_n-- ) (IGNORED) putc( get_char(), stderr); +} +>>> + +\<special resolution err\><<< +warn_i_int( 26, '!'); +(IGNORED) putc( ch, stderr); +while( special_n-- ) (IGNORED) putc( get_char(), stderr); +>>> + + + +\<consume unused specials\><<< +while( special_n-- ) (void) get_char(); +>>> + + +\<unused special\><<< +; +>>> + + +\<header functions\><<< +static void show_err_context( ARG_I(void) ); +>>> + +\<functions\><<< +static void show_err_context(MYVOID) +{ long curr_pos; + int n, i; + U_CHAR ch; + if( err_context ){ + curr_pos = ftell(dvi_file); + for(n=6; n--;){ + (IGNORED) putc( '\n', stderr ); + for(i=70; i--;){ + ch = get_char(); + (IGNORED) putc(( (ch>31) && (ch<127))? ch : ' ', stderr); + } + } + (IGNORED) fseek(dvi_file, curr_pos, `<abs file addr`>); + (IGNORED) putc( '\n', stderr ); (IGNORED) putc( '\n', stderr ); + if( err_mark ){ print_f( err_mark ); } +} } +>>> + + + +A static informs that the function is defined just locally, preventing +possible errors when the linker detects name conflicts with definitions +that use the same names in other libraries. + +\<static\><<< +static +>>> + +\<vars\><<< +static BOOL err_context = FALSE; +>>> + +\<context for warn and errs\><<< +err_context = TRUE; +>>> + + + + + + + + +\SubSection{Trace Errors} + +\<vars\><<< +static U_CHAR *err_mark = (char *) 0; +>>> + +\<get err str\><<< +if( err_mark ){ free((void *) err_mark); } +if( special_n ){ + err_mark = get_str( (int) special_n ); special_n=0; +} else { err_mark = (char *) 0; } +>>> + + + +\SubSection{Trace Specials} + + +\<trace specials in dvi\><<< +trace_special = TRUE; +>>> + +\<vars\><<< +static BOOL trace_special = FALSE; +>>> + + +On off with \''\special{t4ht@/}' + +\<on/off special trace\><<< +trace_special = !trace_special; +>>> + + +\<trace specials\><<< +{ long curr_pos; + int n, i; + U_CHAR ch; + + curr_pos = ftell(dvi_file); + print_f("\nSPECIAL: "); ch = special_hd[8]; i=60; + for( n=*special_n - 3; n--;){ + if( !i ){ (IGNORED) putc( '\n', cur_o_file ); i=70; } + else i--; + (IGNORED) putc(( (ch>31) && (ch<127))? ch : ' ', cur_o_file); + ch = get_char(); + } + (IGNORED) putc( '\n', cur_o_file ); + (IGNORED) fseek(dvi_file, curr_pos, `<abs file addr`>); +} +>>> + + + + + + +\Section{Dos} + + +\List{disc} + +\item +\''open(file, ..._FLAGS)': All +text files should be opened with "r" or "w"; all binary files with "rb" +or "wb". This is the portable way and will work both under Unix and DOS; +as Unix doesn't distinguish between text and binary files, its compilers +will simply ignore the "b" part. + +Unix doesn't differentiate between binary binary and text files. + + + In general, the rule of thumb is that DOS/Windows ports should recognize + both back- and forward-slashes in their input (such as command-line + arguments), but can construct file names by using forward slashes alone + (since DOS/Windows kernels support both styles). + + On the subject of the .lg file: you open the tex4ht.env file in binary +mode ("rb"), which results in strange line endings in the .lg file +(CR/CR/LF). Changing the mode to "r" fixes this. + +\''(WRITE_BIN_FLAGS, READ_BIN_FLAGS)': Use binary mode with DJGPP. ---captured with the \''__MSDOS__'. + + +\<defines\><<< +#if defined(DOS_WIN32) || defined(__MSDOS__) +#define READ_BIN_FLAGS "rb" +#define READ_TEXT_FLAGS "r" +#define WRITE_BIN_FLAGS "wb" +#ifdef WIN32 +#define WRITE_TEXT_FLAGS "wb" +#else +#define WRITE_TEXT_FLAGS "w" +#endif +#else +#define READ_BIN_FLAGS "r" +#define READ_TEXT_FLAGS "r" +#define WRITE_BIN_FLAGS "w" +#define WRITE_TEXT_FLAGS "w" +#endif +>>> + + + +\Verbatim +I've been held up a bit by a +bug in tex4ht.c that caused emTeX to complain that the created .idv file +was corrupt: + +*** Fatal error 2106: corrupt DVI file (postamble not found) + + I found the cause, though: you open it with mode "w", which is text +mode. Changing this to "wb" solved the problem. +\EndVerbatim + + +\item Argument types in declaration of functions + +Function prototypes + +\<tex4ht.h\><<< +#ifdef DOS +#define PROTOTYP +#endif +#ifdef ANSI +#define PROTOTYP +#endif +#ifdef KWIN32 +#define PROTOTYP +#endif +>>> + +\<defines\><<< +#ifdef PROTOTYP +#define MYVOID void +#define ARG_I(x) x +#define ARG_II(x,y) x,y +#define ARG_III(x,y,z) x,y,z +#define ARG_IV(x,y,z,w) x,y,z,w +#define ARG_V(x,y,z,w,v) x,y,z,w,v +#define ARG_VI(x,y,z,w,v,u) x,y,z,w,v,u +#define ARG_VII(x,y,z,w,v,u,t) x,y,z,w,v,u,t +#else +#define MYVOID +#define ARG_I(x) +#define ARG_II(x,y) +#define ARG_III(x,y,z) +#define ARG_IV(x,y,z,w) +#define ARG_V(x,y,z,w,v) +#define ARG_VI(x,y,z,w,v,u) +#define ARG_VII(x,y,z,w,v,u,t) +#endif +>>> + +\EndList + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\Section{Op Codes of Dvi} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\<insert rule + move op\><<< +132 >>> + + + +\<insert rule + nomove op\><<< +137 >>> + +\<no op\><<< +138 >>> + +\<start page op\><<< +139 >>> + +\<end page op\><<< +140 >>> + +\<sv loc op\><<< +141 >>> + +\<retrieve loc op\><<< +142 >>> + +\<mv hor 1-byte\><<< +143 >>> + +\<mv hor 2-byte\><<< +144 >>> + +\<mv hor 3-byte\><<< +145 >>> + +\<mv hor 4-byte\><<< +146 >>> + +\<mv hor dist dx.1\><<< +147 >>> + +\<dx.1 store and mv hor 1-byte\><<< +148 >>> + +\<dx.1 store and mv hor 2-byte\><<< +149 >>> + +\<dx.1 store and mv hor 3-byte\><<< +150 >>> + +\<dx.1 store and mv hor 4-byte\><<< +151 >>> + +\<mv hor dist dx.2\><<< +152 >>> + +\<dx.2 store and mv hor 1-byte\><<< +153 >>> + +\<dx.2 store and mv hor 2-byte\><<< +154 >>> + +\<dx.2 store and mv hor 3-byte\><<< +155 >>> + +\<dx.2 store and mv hor 4-byte\><<< +156 >>> + +\<mv ver 1-byte\><<< +157 >>> + +\<mv ver 2-byte\><<< +158 >>> + +\<mv ver 3-byte\><<< +159 >>> + +\<mv ver 4-byte\><<< +160 >>> + +\<mv ver dist dy.1\><<< +161 >>> + +\<dy.1 store and mv ver 1-byte\><<< +162 >>> + +\<dy.1 store and mv ver 2-byte\><<< +163 >>> + +\<dy.1 store and mv ver 3-byte\><<< +164 >>> + +\<dy.1 store and mv ver 4-byte\><<< +165 >>> + +\<mv ver dist dy.2\><<< +166 >>> + +\<dy.2 store and mv ver 1-byte\><<< +167 >>> + +\<dy.2 store and mv ver 2-byte\><<< +168 >>> + +\<dy.2 store and mv ver 3-byte\><<< +169 >>> + +\<dy.2 store and mv ver 4-byte\><<< +170 >>> + + +\<font 0\><<< +171 >>> + +\<eof op\><<< +223 >>> + +\<font 63\><<< +234 >>> + +\<number of direct fonts\><<< +63 >>> + +\<font 1-byte\><<< +235 >>> + +\<font 2-bytes\><<< +236 >>> + +\<font 3-bytes\><<< +237 >>> + +\<font int\><<< +238 >>> + +\<special 1\><<< +239 >>> +\<special 2\><<< +240 >>> +\<special 3\><<< +241 >>> +\<special 4\><<< +242 >>> + + +\<def 1 byte font\><<< +243 >>> + +\<def 2 byte font\><<< +244 >>> + +\<def 3 byte font\><<< +245 >>> + +\<def 4 byte font\><<< +246 >>> + +\<start preamble op\><<< +247 >>> + +\<begin-postamble op\><<< +248 >>> + +\<end-postamble op\><<< +249 >>> + + + + +\<start of preamble op\><<< +247 >>> + + + +The ops 250--255 have no meaning in dvi. + + + +\<xdv-pic-file op\><<< +251 +>>> + + + +\<xdv-native-font-def op\><<< +252 +>>> + + + +\<xdv-glyph-array op\><<< +253 +>>> + + +\<xdv-glyph-string op\><<< +254 +>>> + + + +%%%%%%%%%%%%%%%%%% +\Chapter{References} +%%%%%%%%%%%%%%%%%% + + + +\Link[http://www.eskimo.com/\string~scs/C-faq/top.html]{}{}comp.lang.c\EndLink +{ \tt --} +\Link[http://www.cs.tut.fi/\string~leopold/Boar/AnsiLib]{}{}AnsiLib\EndLink + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%%%Line break needed for #defines !!!! + + + + + + +\Comment{ +/*}{*/ +} +\ifx \export\:UnDef \else +\Comment{ +}{} +\fi + + + \OutputCodE\<tex4ht.c\> + + +\bye + |