summaryrefslogtreecommitdiff
path: root/support/TeX4ht/source/tex4ht-c.tex
diff options
context:
space:
mode:
Diffstat (limited to 'support/TeX4ht/source/tex4ht-c.tex')
-rw-r--r--support/TeX4ht/source/tex4ht-c.tex17542
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
+