-- 私の小道具箱--
平文からのHTML2変換系
若鳥陸夫
(CALS技術研究組合)
Internet(網間)を経由して,WWW放送の内容を作成する場合,
大勢の人から原稿を集め,最終的にHTML文書にする手間がか
かることがある。その主な手間は,文書内・外との関連付け
て投錨(anchoring)する作業に集中している。そこで,簡単な
に目録作成及び外部投錨を自動化する処理系を作成したの
で報告する。プログラム中の仕様不足又は誤りは正して利用
されることを期待して, 作者は一切の責任を負わない。
目録
1.はじめに
1.1 HTML文書の作成手段
1.2 利用者要件
2.HTML変換系の前提
2.1 HTML変換系の位置付け
2.2 原始文書の様式
2.3 投錨の指示
2.4 目的文書の様式
3.HTML変換規則の要約
4.おわりに
付録1.(原始文書例)
付録2.(投錨指示例)
付録3.(HTML変換後の例)
付録4.(原始プログラム)
CALS関連規格へ戻る。
1.はじめに
1.1 HTML文書の作成手段
WWWでの放送を目標とする文書の作り方には,次の3とおりの
方法がある。
a)HTML主導編集系
b)ワードプロセッサで入力し,HTML変換する。
c)文面(text)編集系で作成後,HTML変換する。
HTML編集系によれば,HTML文書を直接作成できる。しかし,
その作者が,他の入力編集系も併用していた場合,複数の入力
の操作に習熟する必要がある。
ワードプロセッサで作成した文面(割付け付き)からHTML
変換する方法は,使いなれた入力系を利用できるので,新しく
操作を憶えなくてもよさそうに見える。しかし,HTMLへ変換
して見た結果が,思い通りでなかったら,再度,原文から手直し
しなければならない。また,その原稿は,特定の処理系に依存
した様式のままでは,Internet 世界の規範に外れる。
文面編集系で作成後,HTML変換する方法は,原稿が文面だけ
だから,Internetを経由して,遠隔地との間でもInternet経由
で文書交換ができる。
これらの事項を勘案して,NCALSでは,b)とc)との2とおり
によって,HTML文書を作ってきた。ここでは,そのうち,c)の
方法を紹介する。
1.2 利用者要件
a)利用者は,文章が簡単に入力できる。
b)文書の冒頭に目録(案内)が自動生成される。
c)文書の内部・外部との関連を別途指示すれば,その箇所に
投錨する。
d)絵・写真の挿入は,別途,編集して追加することとし,ここ
では,除外する。
e)操作系は,Unix(Solaris),MS-Windows95のいずれでもよい。
f)広報を目的とするため,HTML水準は,IETF-HTML2.0に低く
押さえる。
2.HTML変換系の前提
2.1 HTML変換系の位置付け
ここで,紹介するHTML変換系は,次の事項を前提としている。
すなわち,計算機対利用者間の界面は,よいものが別途用意さ
れると考える。
2.1.1 前処理
2.1.1.1 文面ファイルの作成
変換対象の文面ファイルは,何らかの手段によって,生成され
ているとする。
2.1.1.2 投錨指示ファイルの作成
何らかの対話的な手段によって,投錨の手掛かりとなる鍵語
及び置換する字句の並び(list)が用意されているとする。
2.2 原始文書の様式
2.2.1 見出しの様式
原始文書の様式に規範を加えて,目録生成のための手掛かりと
した。その手掛かりとは,行頭に数字とピリオドとの組み合わせ
があれば,章・節・項・号の見出し行と見なす。
例: 1.1 第1章第1節の見出し
2.2.2 行の長さ
行の長さを処理系に任せてもよいと判断した部分の文の長さは,
自由とする。この場合,処理系は,省略時値として,35文字で強制
改行を付加する。
2.2.3 文字集合及び符号
使える文字種は,英数字(ASCII)及びJIS漢字だけとする。この中
には,1バイト片仮名文字を使用してはならない。
符号系は,シフトJIS及びEUCを指示する。
2.2.4 行末符号
文の行末(段落の末)の符号は,LF(0x0A)とする。
2.3 投錨の指示
投錨する用語は,別途,次のとおりの様式で作成されている。
なお,同じ用語から始まる鍵語は,長い方を上に列挙する(最長
一致法を指示)。
例 鍵語 置き換え文字列
段落の並び setOfPara.html
段落 para.html
2.4 目的文書の様式
目的文書の様式は,IETF-HTML2.0とする。この様式によれば,
世間の大抵の閲覧系(brawzer)で再生できる。
3.HTML変換規則の要約
a)HTML文書は,頭部(head)と体部(body)との構造とする。
b)頭部の見出し語は,指定された原始文書のファイル名を入れる。
c)原文を走査しながら
1)行頭で見出し語があれば,錨の属性として順序数を記憶させ、
見出し語を挟んだ投錨を記述する。
<A HREF="#名前")>第1章見出し</A>
2)最初から原文を走査しながら,行頭の直前に錨の属性"NAME"に
1)で作成した順序数を付加する。
<A NAME="名前">
3)原文書を走査しながら,HTML構文文字を,文字参照に置き換える。
i)""" --> """
ii)"<" --> ">"
iii)">" --> "<"
4)強制改行の付加
原文書を分割して35文字で強制改行"
"を付加する。
5)文書の末尾には,その文書の最初に戻る投錨及びその文書群
の最初の案内へもどれるように投錨を追記する。
6)原文書を最初から走査しながら,文字が出現するごとに,
投錨指示の鍵語群と比較し,もし等しい字句が発見されれば,
置き換え文字列と組み合わせて投錨する。
<A HREF="置き換え文字列">鍵語</A>
もし,一致する鍵語がなければ読み取った文字を目的ファイル
へ複製する。
4.おわりに
このHTML変換系は,平文を用意した後,煩雑な手作業を必要と
することが多い投錨の一部が機械に代替させることを支援する。
したがって,著者は,どの用語をどこに結合すれば効果的かとか,
文書の目録としてもらいたい章建てなどより本質的な著作活動
に力を注ぐことができる。実際,筆者は,この処理系に助けられて,
約300 ファイルの保守を研究の片手間で実施できるようになった。
しかし,原文書の様式に規範が必要であるから,この規範で書ける
文書類又はこの規範に沿って書ける著者までしか応用できない
欠点もある。
試用した結果,この原稿のようにHTML文そのものが含まれる文書
には,文字参照としてアンパーサンド"&;"の追加が必須であることが判明
し,追加した。その他,そのような特殊な文書の処理では,手修正か
原始プログラムを修正して,使われたい。いずれにしても,結合数の
加減などの手修正を前提としている。
------------------------------------------------------------
付録1.(原始文書例)
1.第1章
1.1 第1章第1節
段落の並び
1.2 第1章第2節
段落の並び
2.第2章
2.1 第2章第1節
段落
------------------------------------------------------------
付録2.(投錨指示例)
項 para0.html
段落の並び setOfPara.html
段落 para.html
------------------------------------------------------------
付録3.(HTML変換後の例)
<HTML>
<HEAD>
<TITLE>test.txt</TITLE>
</HEAD>
<BODY>
<A NAME="top">
=== Contents === <BR>
<A HREF="#0">1.第1章</A><BR>
<A HREF="#1">1.1 第1章第1節</A><BR>
<A HREF="#2">1.2 第1章第2節</A><BR>
<A HREF="#3">2.第2章</A><BR>
<A HREF="#4">2.1 第2章第1節</A><BR>
<A HREF="i;index.html">Return to directory</A><BR>
<BR>
<A NAME="0">
<H4>1.第1章</H4>
<A NAME="1">
<H4>1.1 第1章第1節</H4>
<A HREF="setOfPara.html">段落の並び</A><><BR>
<A NAME="2">
<H4>1.2 第1章第2節</H4>
<A HREF="setOfPara.html">段落の並び</A><BR>
<A NAME="3">
<H4>2.第2章</H4>
<A NAME="4">
<H4>2.1 第2章第1節</H4>
<A HREF="para.html">段落</A><BR>
<BR>
<A HREF="#top">Return to top</A><BR>
<A HREF=index.html>Return to directory</A><BR>
</BODY>
<:/HTML>
------------------------------------------------------------
付録4.(原始プログラム)
/*////////////////////////////////////////////////////////////*/
/*This program translates a text document into HTML2 document.*/
/* Copyright(C) 1997 PCUA. All rights reserved. */
/* Copyright(C) 1998 NCALS. All rights reserved. */
/*/////////////////////////////////////////////////////V1R03//*/
/* The following input form are expected in the program. */
/* A) Source file: 1) Pre-formatted text in EUC or SJ, */
/* 2) The file name will be used at title */
/* of Header in HTML. */
/* 3) Body emphasis format: */
/* Start: Number include a period. */
/* End : End of the line. */
/* The emphsis lines will be listed as */
/* as index at top the HTML document. */
/* B) Link file 1) List of a pair of two strings */
/* (OPTION) separated by a space. This pair */
/* specifies for creation of an anchor. */
/* Format : keyword URL */
/* 2) Most longest keyword shall be listed */
/* at first, if a same string consists */
/* in the keywords. */
/* Examples of inclusion of a same A */
/* AB FileA.html#AB */
/* A FileA.html#A */
/*////////////////////////////////////////////////////////////*/
#include <stdio.h>
/*#include <iostream.h> */
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
/*The following are the default value list. */
#define MAXchar "35"
#define MAXtitle "15"
/* The following two constant define numbering system. */
#define STYLEtitle "N"
#define STYLEsep "."
/*Figure may be supported in the future using the value. */
#define STYLEfigure "Figure"
/*Platform specifies the character code system,EUC or SJ. */
#define Platform "EUC"
/*Temporal file will be used in the process. */
#define Tmp "tmp.htm"
/*keyword list can be monitored if change to "on" */
#define Monitor "off"
/*The following are assignment of the specific code value.*/
#define LF 0x0A
#define CR 0x0D
#define SP 0x20
#define QT 0x22
#define ERO 0x26
#define MN 0x2D
#define LT 0x3C
#define GT 0x3E
/*Definitions of the functions */
#define spc(c) ((((c)==LF)||((c)==CR)||((c)==SP))?-1:0)
#define nl(c) (((c==LF)||((c)==CR))?-1:0)
/*Code range test function, but are not correct method */
#define isSJ(c) ((((c)&0x80)!=0)?-1:0)
#define isEUC(c)((((c)&0x80)!=0)?-1:0)
/*Wide character type "wchar_t" is defined for non supported*/
/*processors. */
#define wchar_t unsigned
/*Maximum number of keyword list */
#define MAXKEY 10
/*String array size */
#define M 256
/*Variables */
char maxChar[M], maxTitle[M], s[M], platform[M], tmp[M];
char sTitle[M], hdDes[M], sTable[M], sFigure[M], monitor[M];
wchar_t temp[M];
struct kt { wchar_t keys[M],alts[M]; int next; };
struct kt key[MAXKEY];
int ln=0,ib=0,ib_len_min=5000,ib_max=4000;
int mkLink=-1, object=-1,header=-1;
FILE *fi,*fr,*fo,*ft;
/* reverse a string */
void reverse(char s[M])
{ int c,i,j;
for (i=0, j=strlen(s)-1; i<j;i++,j--){
c=s[i]; s[i]=s[j]; s[j]=c;
}
} /* reverse */
/* Converts an integer into string. This may be included as standards */
void itoa(int n, char s[M], int radix)
{ int i, sign;
if ((sign=n) < 0)
n=-n;
i=0;
do {
s[i++]=n % radix + '0';
} while ((n /= radix)>0);
if (sign < 0)
s[i++]='-';
s[i]=(char)NULL;
reverse(s);
} /* itoa */
/* Converts a single character into a wide character */
wchar_t c2w(char c)
{
return ((wchar_t)c);
} /* c2w */
/* Converts to a wide character into wode character string */
wchar_t *w2s(wchar_t c)
{
temp[0]=c; temp[1]=(wchar_t)NULL;
return (temp);
} /* w2s */
/* Displays an error message */
void errorM(char msg[M])
{
printf("%s\n", msg);
} /* errorM */
/* Entry format throughout the program if applicable */
void entry(char msg[M], char emsg[M])
{
printf("Enter %s", msg); scanf("%s", emsg);
} /* entry */
/* Return number of character of the wide character string */
int wstrlen(wchar_t s[M])
{ register int i=0,j=0,eol=0;
while((i<M)&&(!eol)){
if (s[i]==(wchar_t)NULL) eol=-1;
else j++;
i++;
}
return j;
} /* wstrlen */
/* Comparison between the wide character strings */
int wstrcmp(wchar_t s[M],wchar_t t[M])
{ register int i,j,k=0;
i=wstrlen(s); j=wstrlen(t);
if ((i==0)||(j==0)) return 0;
else if (i < j) return 0;
else if (i > j) return 0;
else {
for(k=0;k<i;k++)
if (s[k]!=t[k]) return 0;
return -1;
}
} /* wstrcmp */
/* Concatenation of the wide character strings */
void wstrcat(wchar_t s[M],wchar_t w[M])
{ register int i=0,j=0,k=0;
i=wstrlen(s); j=wstrlen(w);
while (k<j){
s[i+k]=w[k]; k++; /* copy the string after s */
}
s[i+j]=(wchar_t)NULL; /* end mark */
} /* wstrcat */
/* Write a wide character in the file */
void wprint(FILE *f, wchar_t *s)
{ register int i,j=0;
wchar_t w;
j=wstrlen(s);
if (f==stdout) object=0;
for (i=0;i<j;i++){
w=*s>>8;
if (((strcmp(platform,"EUC")==0)&&(isEUC((unsigned)w)))||
((strcmp(platform,"EUC")!=0)&&(isSJ((unsigned)w)))) {
if (object!=0)
fprintf(f,"%c%c",(char)w,(char)(*s & 0x00FF));
if (strcmp(monitor,"on")==0)
printf("%c%c",(char)w,(char)(*s & 0x00FF));
}
else {
if (object!=0)
fprintf(f,"%c",(char)*s);
if (strcmp(monitor,"on")==0)
printf("%c",(char)*s);
}
s++;
}
} /* wprint */
/* Display the keyword list for monitoring */
void printKeys(wchar_t w)
{ int i=0,j;
struct kt *k;
char fk[M];
printf("[Keywords and the alter are as follows:]\n");
j=(w & 0x00FF);
k=&key[0];
while ((k[i].keys!=(wchar_t)NULL)&&(i<j)){
printf("[keys[%d]=",i); wprint(stdout,k[i].keys); printf(",");
printf("[alts[%d]=",i); wprint(stdout,k[i].alts); printf("]\n");
i++;
}
entry("'y' if the list of keys is OK ",fk);
} /* printKeys */
/* Gets and makes a wide character string from byte string */
wchar_t wfgetc(FILE *f)
{ int c;
wchar_t w;
c=fgetc(f);
if (((strcmp(platform,"EUC")==0)&&(isEUC(c)))||
((strcmp(platform,"EUC")!=0)&&(isSJ(c)))) /* Kanji code */
w=((c&0x00FF) << 8 ) | (wchar_t)fgetc(f);/* Read 2nd byte */
else w=(wchar_t)c;
return (w);
} /* wfgetc */
/* Converts traditional string into wide character string */
wchar_t *s2w(char s[M])
{ register int i;
for (i=0;i<strlen(s);i++)
temp[i]=(wchar_t)s[i];
temp[i]=(wchar_t)NULL;
return (temp);
} /* s2w */
/* Extract wchar_t string from m to n */
wchar_t *extractC(wchar_t k[M],int m,int n)
{ int i=0,j=0;
i=m;
while ((k[i]!=(wchar_t)NULL)&&(i<=n)){
temp[j]=k[i];
i++; j++;
}
temp[j]=(wchar_t)NULL;
return (temp);
} /* extractC */
/* Copy the wide character string */
void wstrcpy(wchar_t *t,wchar_t *s)
{ register int i,j;
j=wstrlen(s);
for (i=0;i<=j;i++)
*t++=*s++;
} /* wstrcpy */
/* Find a place for storing of the keyword then store it */
void putKey(wchar_t m[M], wchar_t n[M],int i)
{ struct kt *k;
k=&key[0];
while (wstrcmp(k[i].keys,(wchar_t)NULL)==0) i=k[i].next;
wstrcpy(k[i].keys,m); wstrcpy(k[i].alts,n);
k[i].next=(wchar_t)NULL;
} /* putKey */
/* Looking for the keyword in the list of keyword */
void getKey(wchar_t m[M],wchar_t n[M],int i)
{ struct kt *k;
k=&key[0];
while ((wstrcmp(k[i].keys,(wchar_t)NULL)==0)&&
(wstrcmp(k[i].keys,m)==0)) i=k[i].next;
if (wstrcmp(k[i].keys,m)) wstrcpy(n,k[i].alts);
else n[0]=(wchar_t)NULL;
} /* getKey */
/* Puts the anchors as listed link keyword */
int prepLink(char *r)
{ register int i,m=M,step=0;
wchar_t c;
struct kt *k;
FILE *fr;
k=&key[0];
/* Clears all key tables */
for (i=0;i<MAXKEY;i++){
*k[i].keys=(wchar_t)NULL;
*k[i].alts=(wchar_t)NULL;
k[i].next=(int)NULL;
}
/* Reads the link file */
if ((fr=fopen(r,"r"))==NULL){
errorM("Link file can not be open.");
return(0);
}
else { /* Link file exists */
ib_max=0; c=(wchar_t)NULL;
k=&key[0];
while ((c=wfgetc(fr))!=(wchar_t)EOF){
switch(step){
case 0 : { /* step==0 */
if (!spc((char)c)){ /* search for key*/
wstrcat(k[ib_max].keys,w2s(c));
}
else step=1; /* skip leading spaces */
} break;
case 1 : { /* step==1 */
if (!spc(c)) {
step=2; /* copy alternative string */
wstrcpy(k[ib_max].alts,w2s(c));
/* store a minimum length of keys */
m=wstrlen(k[ib_max].keys);
if (m<ib_len_min) ib_len_min=m;
}
} break;
case 2 : { /* step==2 */
if (!spc(c)){ /* search for alter */
wstrcat(k[ib_max].alts,w2s(c));
}
else step=3; /* skip spaces between key and alter */
} break;
case 3 :{ /* search for next key */
step=0; ib_max++;
wstrcat(k[ib_max].keys,w2s(c));
} break; /* alter && spc */
} /* switch */
}
fclose(fr);
if (strcmp(monitor,Monitor)!=0) printKeys(ib_max);
return (-1);
} /* no link file exists */
} /* prepLink */
/* Set default value to the specified valuables */
void prepare(char maxChar[M], char maxTitle[M],
char sTitle[M], char hdDes[M], char sFigure[M],
char r[M], char tmp[M])
{ char fk[M];
/* Default values */
strcpy(maxChar,MAXchar);
strcpy(maxTitle,MAXtitle);
strcpy(sTitle,STYLEtitle);
strcpy(hdDes,STYLEsep);
strcpy(sFigure,STYLEfigure);
strcpy(platform,Platform);
strcpy(tmp,Tmp);
strcpy(monitor,Monitor);
do {
printf(" === Select parameters ===\n");
printf(" 1. Maxmum characters per line : %s\n",maxChar);
printf(" 2. Maximum of titles for link : %s\n",maxTitle);
printf(" 3. Style for title(A / N) : %s\n",sTitle);
printf(" 4. Separator of title(period) : %s\n",hdDes);
printf(" 5. Code system (EUC or SJ) : %s\n",platform);
printf(" 6. Temporally file name : %s\n",tmp);
printf(" 7. Monitor link word (on /off): %s\n",monitor);
entry("either a number for change or 'y' for unchange",fk);
switch((char)fk[0]){
case '1': entry("Maximum length of line",maxChar); break;
case '2': entry("Maximum title for link",maxTitle); break;
case '3': entry("Style for title(A / N)",sTitle); break;
case '4': entry("Separator of title ",hdDes); break;
case '5': entry("Code in the document ",platform); break;
case '6': entry("Temporally file name ",tmp); break;
case '7': entry("Monitor on / off ",monitor); break;
case 'y' :
case 'Y' : break;
default : printf(" Default values are used.\n"); break;
}
} while ((char)fk[0]!='y');
mkLink=prepLink(r);
} /* prepare */
/* Makes the header part in the HTML file. */
void putHead(char title[M])
{
wprint(ft,s2w("<HTML>\n"));
wprint(ft,s2w("<HEAD>\n"));
wprint(ft,s2w("<TITLE>"));
wprint(ft,s2w(title));
wprint(ft,s2w("</TITLE>\n"));
wprint(ft,s2w("</HEAD>\n"));
} /* putHead */
/* Replaces the syntactical characters in the header */
void chgStore(wchar_t s[M],wchar_t c)
{
switch((char)c){
case LT : wstrcat(s,s2w("<")); break;
case GT : wstrcat(s,s2w(">")); break;
case MN : wstrcat(s,s2w("−")); break;
case QT : wstrcat(s,s2w(""")); break;
case ERO: wstrcat(s,s2w("&")); break;
case LF : c=(wchar_t)NULL; wstrcat(s,s2w("<BR>\n"));
break;
case CR : c=(wchar_t)NULL; break;
default : wstrcat(s,w2s(c));
}
} /* chgStore */
/* Looking for header pointer specified by "c". */
int isHeader(wchar_t c[M],wchar_t s[M])
{ register int f=0, i=0;
while (i<wstrlen(s))
if (c[0]==s[i++]) f=-1;
return f;
} /* isHeader */
/* Creates a header and add emphasis */
wchar_t heading(char *hdDes,wchar_t c)
{ wchar_t s[M];
char t[M];
if (ln < (int)maxTitle){
wstrcpy(s,w2s(c2w(c)));
while (((c=wfgetc(fi))!=(wchar_t)EOF)&&(!nl(c)))
chgStore(s,c);
if (isHeader(extractC(s2w(hdDes),0,0),s)!=0){
itoa(ln++,t,10);
wprint(ft,s2w("<A HREF="));
wprint(ft,w2s(c2w(QT)));
wprint(ft,s2w("#"));
wprint(ft,s2w(t));
wprint(ft,w2s(c2w(QT)));
wprint(ft,w2s(c2w(GT)));
wprint(ft,s);
wprint(ft,s2w("</A><BR>\n"));
} /* is_a */
}
return (c);
} /* heading */
/* Put a name attribute of anchor at the header */
void putName(wchar_t c)
{ wchar_t s[M];
char t[M];
register int i=0;
s[i++]=c; s[i]=(wchar_t)NULL;
if (ln < (int)maxTitle){
while (((c=wfgetc(fi))!=(wchar_t)EOF)&&(!nl(c))){
chgStore(s,c);
} /* while */
if (isHeader((extractC(s2w(hdDes),0,0)),s)!=0){
itoa(ln++,t,10);
wprint(ft,s2w("<A NAME="));
wprint(ft,w2s(c2w(QT)));
wprint(ft,s2w(t));
wprint(ft,w2s(c2w(QT)));
wprint(ft,w2s(c2w(GT)));
wprint(ft,s2w("\n"));
wprint(ft,s2w("<H4>"));
wprint(ft,s);
wprint(ft,s2w("</H4>\n"));
} /* is_a */
else {
wprint(ft,s);
wprint(ft,s2w("<BR>\n"));
}
} /* ln < maxTitle */
} /* putName */
/* Replaces the syntical character by character reference and */
/* creates a name for the header as an attributes of anchor. */
void copyBody()
{ register wchar_t c;
ln=0;
while ((c=wfgetc(fi))!=(wchar_t)EOF){
switch(c){
case LT : wprint(ft,s2w("<")); break;
case GT : wprint(ft,s2w(">")); break;
case MN : wprint(ft,s2w("−")); break;
case QT : wprint(ft,s2w(""")); break;
case ERO: wprint(ft,s2w("&")); break;
case LF : c=(wchar_t)NULL; wprint(ft,s2w("<BR>\n")); break;
case CR : c=(wchar_t)NULL; putName(c); break;
default : putName(c);
}
}
} /* copyBody */
/* Delates leading spaces */
wchar_t deleteSP(FILE *f,wchar_t c)
{ register i=0;
if (spc(c)){
while ((spc(c))&&(c!=(wchar_t)EOF)&&(i++<=(int)maxTitle))
c=wfgetc(f);
}
return (c);
} /* deleteSP */
/* Searches a header form in the text string */
void searchHeader(char *hdDes)
{ register wchar_t c;
int line=0,charPos=0;
while ((c = wfgetc(fi))!=(wchar_t)EOF){
if (nl(c)){
line++; charPos=0;
}
else if (charPos<1) {
c=deleteSP(fi,c);
if (strcmp(sTitle,"N")==0){ /* Numeric header */
switch((char)c){
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9': case '0':
c=heading(hdDes, c); charPos=0; break;
default : charPos++;break;
}
}
else { /* Non-numeric header */
if (strcmp(sTitle,"A")==0){
c=heading(hdDes, c); charPos=0;
}
else charPos++;
} /* Non-numeric header */
} /* fi (charPos<1) */
} /* while not EOF */
} /* searchHeder */
/* Put the tail data for the HTML file. */
void putTail(void)
{
wprint(ft,s2w("<A HREF="));
wprint(ft,w2s(c2w(QT)));
wprint(ft,s2w("#top"));
wprint(ft,w2s(c2w(QT)));
wprint(ft,s2w("<Return to top</A><BR>\n"));
wprint(ft,s2w("<A HREF="));
wprint(ft,s2w("index.html"));
wprint(ft,s2w("<Return to directory</A><BR>\n"));
wprint(ft,s2w("</BODY>\n>));
wprint(ft,s2w("</HTML>\n"));
} /* putTail */
/* Translates the text file into HTML file */
void t2h(void)
{
copyBody();
putTail();
} /* t2h */
/* Makes the list of contents at the beginning of BODY */
void contents(char *hdDes)
{
wprint(ft,s2w(&quit;<BODY<\n>));
wprint(ft,s2w("<A NAME="));
wprint(ft,w2s(c2w(QT)));
wprint(ft,s2w("top"));
wprint(ft,w2s(c2w(QT)));
wprint(ft,s2w(">\n"));
wprint(ft,s2w(" === Contents === <BR>\n"));
searchHeader(hdDes);
wprint(ft,s2w("<A HREF="));
wprint(ft,w2s(c2w(QT)));
wprint(ft,s2w("index.html"));
wprint(ft,s2w("<Return to directory</A><BR>\n"));
wprint(ft,s2w("<BR>\n>));
} /* contents */
/* Reads out link data specified by position-i */
int rdLink(int i,wchar_t k[M],wchar_t a[M])
{ struct kt *kw;
kw=&key[0];
wstrcpy(k,kw[i].keys); wstrcpy(a,kw[i].alts);
return (k[0]);
} /* rdLink */
/* Adds a link if the keyword found in the temporally file. */
/* Otherwise copy temporal file(ft) to object file(o) */
void addLink(FILE *ft, FILE *fo)
{
wchar_t c;
int f=0,i=0,j;
wchar_t k[M]; //keyword for link */
wchar_t a[M]; //alter word */
wchar_t w[M]; //word extracted from temporal file */
wchar_t x[M]; //extracted word from string */
w[0]=(wchar_t)NULL; ib=0;
while (((c=wfgetc(ft))!=(wchar_t)EOF)&&(!spc(c))) {
wstrcat(w,w2s(c)); //separated by space
}
i=0; j=wstrlen(w); x[0]=(wchar_t)NULL;
while ((i<=j)&&(c!=(wchar_t)EOF)){
while (i<=j){
wstrcat(x,extractC(w,i,j));
f=0;
if (wstrlen(x)>0) {
while (((rdLink(ib,k,a))!=(wchar_t)'\n')&&
(!f)&&(ib<=ib_max)){ //loop until final keyword
wstrcpy(temp,extractC(x,0,wstrlen(k)-1));
if (((f=wstrcmp(temp,k))==0)||(wstrlen(k)==0)
||(wstrlen(a)==0)) {
ib++; /*replace the keyword for next comparison */
}
else {/* Adds anchor specified by alternative string */
wprint(fo,s2w("<A HREF=>"));
wprint(fo,w2s(c2w((char)QT)));
wprint(fo,a);
wprint(fo,w2s(c2w((char)QT)));
wprint(fo,s2w(">"));
wprint(fo,k);
wprint(fo,s2w("</A>"));
x[0]=(wchar_t)NULL; ib=0; i+=wstrlen(k);
} /* else */
} /* while rdLink times(ib) < ib_max */
} /* fi (wstrlen(x) > 0) */
if (!f) wprint(fo,w2s(w[i++]));
x[0]=(wchar_t)NULL; ib=0;
} /* while (i<=j) */
if (i>=j) { //add LF,CR or SP
switch(c){
case LF : wprint(fo,w2s('\n')); break;
case CR : wprint(fo,w2s('\n')); break;
case SP : wprint(fo,w2s(' ')); break;
}
} /* fi (i>=j) */
i++; ib=0;
x[0]=(wchar_t)NULL;
if (i>j){ /* Reads next word for testing */
w[0]=(wchar_t)NULL;
while (((c=wfgetc(ft))!=(wchar_t)EOF)&&(!spc(c))){
wstrcat(w,w2s(c));
}
i=0; j=wstrlen(w);
} /* fi (i>j) */
} /* while !EOF(ft) */
} /* addLink */
/* Analyze the source file then makes HTML files */
void analyzer(char *s,char *o, char *tmp)
{ wchar_t c;
/* 1st pass */
if ((ft=fopen(tmp,"w"))==NULL)
errorM("Temporally file can not be open at 1st pass.");
else {
if ((fi=fopen(s,"r"))==NULL)
errorM("Source file can not be open at 1/2 of 1st pass.");
else {
putHead(s); contents(hdDes); fclose(fi);
if ((fi=fopen(s,"r"))==NULL)
errorM("Source file can not be open at 2/2 of 1st pass.");
else {
t2h(); fclose(fi);
}
}
fclose(ft);
}
/* 2nd pass */
if ((fo=fopen(o,"w"))==NULL)
errorM("The object file can not be open at 2nd pass.");
else {
if ((ft=fopen(tmp,"r"))==NULL)
errorM("The temporally file can not be open at 2nd pass.");
else {
switch (mkLink){
case 0 : while (((c=wfgetc(ft))!=(wchar_t)EOF))
wprint(fo,w2s(c));
fclose(ft); break;
default : addLink(ft,fo); break; //Normal case
}
}
fclose(fo);
}
} /* analyzer */
/* main of linkaid */
int main(void)
{ char src[M], obj[M], lnk[M];
printf("Welcome to LinkAid which transforms text\n");
printf("into HTML form using the link guide.\n");
printf("\n");
entry("a file name for text sorce ",src);
if (strlen(src)==0) {
errorM("Source file shall be specified.");
}
else {
entry("a file name for html object",obj);
object=(strlen(obj)>0);
entry("a file name for link guide ",lnk);
mkLink=(strlen(lnk)>0);
printf("Source=%s\n", src);
if (object!=0) printf("Object=%s\n", obj);
if (mkLink!=0) printf("Link =%s\n", lnk);
prepare(maxChar, maxTitle, sTitle, hdDes, sFigure, lnk, tmp);
analyzer(src, obj, tmp);
printf("[The end of run]\n");
}
return (0);
} /* main */