本文描述的代码在 FireBird 2.5 和 2.6 上均可使用.
代码由 Leeward 于 1998.02.17 在 BBS 水木清华站 开发并运行.
其后在 1998.05.22 和 1998.08.28 进行了改进.
=========================================================================
代码运行需要调用系统中已经正确安装的 tar 和 gzip 命令.
转换后的文章中, 对 URL 能自动生成 HyperLink.
以下假定 Xhtml.c 是本程序的源文件名, 执行代码是 Xhtml, 位于当前目录:
编译指令: make Xhtml
运行指令: ./Xhtml DirPath (参数是要处理的精华区目录相对于当前目录的路径)
可以使用 cron 来完成很多版面精华区的定期自动处理,
并且放置到 WWW 页面中以便下载.
可以直接在
http://bbs.net.tsinghua.edu.cn/BBSMan_Dev/Xhtml.c 下载本文中的代码.
否则, 建议将本文转寄到电子邮件信箱, 再保存并编译.
如果用 telnet 方式直接 Copy/Paste 文中的代码, 可能导致因行长超过 80 字符
而折行从而出现编译错误:-P
=========================================================================
/* Making the X of a board into HTML format and then tar, gzip -- compress. */
/* */
/* Leeward 1998.02.17 (Modified 1998.05.22, 1998.08.28) */
/* */
/* This little program scans a X directory for a board */
/* and converts all its files into HTML format new files */
/* and finally compress the new into a UNIX tgz format package. */
/* */
/* This program uses shell command "ls -AFR" to get a temp control file of */
/* all X directory files, and then convert the recursive directory structure */
/* into a linear structure. */
/* */
/* Also this program duplicates all source files and renames all of them */
/* into digital MS-DOS 8.3 format file names (avoiding easily re-produce). */
/* */
/* Build: */
/* make Xhtml */
/* */
/* Known shortcomings: do not check if disk space is enough */
/* */
#include <stdio.h>
#include <string.h>
#include <sys/mode.h>
#define MAXLINELEN 8192
#define MAXPATHLEN 256
#define MAXFILENUM 1024 /* max directories/files in a directory */
#define DOTNAMES ".Names"
#define INDEXTMP "index.tmp"
#define INDEXHTML "index.htm"
#define HEADER "BBS水木清华站∶精华区"
#define FOOTER "BBS水木清华站∶精华区"
/* Leeward 98.05.22: Use another fixed disk as run-time working directorry;
Do NOT use BBS' data disk space! */
/*#define WORKDIR "/opt/bbsbackup"*/
#define WORKDIR "." /* hehe, since 2GB disk recovered, not using /opt */
/* Leeward 98.08.28: Do not process those boards not public */
#define XBOARDNUM 6
char Xboard[XBOARDNUM][24] = { "deleted", "junk", "syssecurity", "Registry",
"sys_discuss", "Filter"};
int
main(int argc, char **argv)
{
char srcLine[MAXLINELEN] = "", dstLine[MAXLINELEN] = "";
char srcDir[MAXPATHLEN] = "", dstDir[MAXPATHLEN] = "";
char srcFile[MAXPATHLEN] = "", dstFile[MAXPATHLEN] = "";
char srcX[MAXPATHLEN] = "", dstX[MAXPATHLEN] = "";
char anchor[MAXLINELEN] = "";
char Buf[MAXLINELEN] = "", Buf2[MAXLINELEN] = "";
char srcFX[MAXFILENUM][MAXPATHLEN], dstFX[MAXFILENUM][MAXPATHLEN];
char srcDX[MAXFILENUM][MAXPATHLEN];
char srcD[MAXPATHLEN], dstD[MAXPATHLEN];
char cwD[MAXPATHLEN] = "";
char *ptr;
FILE *psrcFile, *pdstFile;
FILE *pDOTNames;
FILE *pINDEXhtml;
FILE *pHasDOTNames;
FILE *pls_AFR;
int NumDir = 0, NumFile = 0;
int NOTsrcX = - 1;
int i, j, k;
time_t now;
printf("This application creates compressed HTML package for BBS.\n");
printf("Initializing...\n");
if (argc < 2)
{
printf("Syntax: %s XDIR\n", argv[0]);
exit(-1);
}
strcpy(srcX, argv[1]);
for (i = 0; i < XBOARDNUM; i ++)
{
ptr = strrchr(srcX, '/');
ptr = ptr ? ptr + 1 : srcX;
if (!strcmp(ptr, Xboard[i]))
{
printf("XDIR \"%s\" forbidden\n", ptr);
exit(-4);
}
}
getcwd(cwD, MAXPATHLEN);
if (chdir(srcX))
{
printf("XDIR \"%s\" not found\n", srcX);
exit(-1);
}
else
{
chdir(cwD);
sprintf(dstX, "%s/%s.AIX", WORKDIR, srcX);
if (mkdir(dstX, 0000755)) /* drwxr-xr-x */
{
printf("Unexpected error: Can not create directory \"%s\"\n", dstX);
exit(-2);
}
strcpy(srcDir, srcX);
sprintf(srcDX[NumDir ++], "%s", srcDir);
}
sprintf(Buf, "ls -AFR %s > %ld.Xhtml", srcX, now = time(0));
system(Buf);
sprintf(Buf, "echo Terminator\":\" >> %ld.Xhtml", now); /* NOT lack last */
system(Buf);
printf("X Starting...\n");
sprintf(Buf, "%ld.Xhtml", now);
if (NULL == (pls_AFR = fopen(Buf, "rt")))
{
printf("Unexpected error: Can not open control file\n");
exit(-3);
}
printf("Processing directory \"%s\"...\n", srcDir);
while (!feof(pls_AFR))
{
fgets(Buf, MAXLINELEN, pls_AFR);
if (feof(pls_AFR))
break;
else
Buf[strlen(Buf) - 1] = 0;
if ('/' == Buf[strlen(Buf) - 1])
{ /* directory */
Buf[strlen(Buf) - 1] = 0;
sprintf(srcDX[NumDir ++], "%s/%s", srcDir, Buf);
if (NumDir >= MAXFILENUM)
{
printf("Fatal error: direcotry number in this X exceeds %s\n", MAXFILENUM);
fclose(pls_AFR);
exit(-3);
}
continue;
}
if (':' == Buf[strlen(Buf) - 1])
{ /* enter a new directory */
Buf[strlen(Buf) - 1] = 0;
strcpy(srcD, srcDir);
NOTsrcX ++;
strcpy(srcDir, Buf);
printf("Finalizing directory \"%s\"...\n", srcD);
sprintf(Buf, "%s/%s", dstDir, INDEXTMP);
if (NULL == (pdstFile = fopen(Buf, "rt")))
{
/*printf("Unexpected error: Can not open file \"%s\"\n", Buf);*/
printf("ATTENTION!!! Directory \"%s\" contains nothing!!!\n", srcD);
continue;
/*fclose(pls_AFR);
exit(-3);*/
}
sprintf(Buf, "%s/%s", dstDir, INDEXHTML);
if (NULL == (pINDEXhtml = fopen(Buf, "wt")))
{
printf("Unexpected error: Can not write file \"%s\"\n", Buf);
fclose(pdstFile);
fclose(pls_AFR);
exit(-3);
}
while (!feof(pdstFile))
{ /* replace URLs in INDEXTMP into digital names */
fgets(dstLine, MAXLINELEN, pdstFile);
if (feof(pdstFile))
break;
else
dstLine[strlen(dstLine) - 1] = 0;
if (ptr = strstr(dstLine, "<A HREF=\""))
{ /* URL lines in INDEXTMP */
char *ptr2 = strstr(ptr + 9, "\">"); /* Leeward: 97.12.15 */
if (NULL == ptr2)
{
printf("Unexpected error: URL analyzation failed\n");
fclose(pINDEXhtml);
fclose(pdstFile);
fclose(pls_AFR);
exit (-4);
}
else
*ptr2 = 0;
for (i = 0; i < NumFile; i ++)
if (!strcmp(ptr + 9, srcFX[i]))
{ /* URL: point a file */
sprintf(Buf, "<A HREF=\"%s\"%s", dstFX[i], ptr2 + 1);
break;
}
*ptr2 = '"';
if (NumFile == i)
{ /* URL: point a directory */
strcpy(Buf, ptr + 9);
ptr = strstr(Buf, "\">");
if (NULL == ptr)
{
printf("Unexpected error: URL analyzation failed\n");
fclose(pINDEXhtml);
fclose(pdstFile);
fclose(pls_AFR);
exit (-4);
}
*ptr = 0;
strcat(srcD, "/");
strcat(srcD, Buf);
for (i = 0; i < NumDir; i ++)
if (!strcmp(srcDX[i], srcD))
{
sprintf(Buf2, "%s/%s", srcDX[i], DOTNAMES);
if (NULL == (pHasDOTNames = fopen(Buf2, "rt")))
{
sprintf(Buf, "<FONT COLOR=RED>此处版主整理精华区时只建了个空目录</FONT><BR>");
ptr = strrchr(srcD, '/');
if (NULL == ptr)
{
printf("Unexpected error: string operation failed\n");
fclose(pINDEXhtml);
fclose(pdstFile);
fclose(pls_AFR);
exit (-4);
}
*ptr = 0;
break;
}
else
{
fclose(pHasDOTNames);
sprintf(dstD, "<A HREF=\"%s/%08d/%s\"%s", (NOTsrcX ? ".." : "."), i, INDEXHTML, ptr + 1);
strcpy(Buf, dstD);
ptr = strrchr(srcD, '/');
if (NULL == ptr)
{
printf("Unexpected error: string operation failed\n");
fclose(pINDEXhtml);
fclose(pdstFile);
fclose(pls_AFR);
exit (-4);
}
*ptr = 0;
break;
}
}
if (i == NumDir)
sprintf(Buf, "<FONT COLOR=RED>此处版主整理精华区时操作错误</FONT><BR>\n");
} /* if (NumFile == i) */
} /* if (ptr = strstr(dstLine, "<A HREF=\"")) */
else
strcpy(Buf, dstLine);
fputs(Buf, pINDEXhtml);
fputs("\n", pINDEXhtml);
}
fclose(pdstFile);
fclose(pINDEXhtml);
sprintf(Buf, "%s/%s", dstDir, INDEXTMP);
unlink(Buf);
printf("Processing directory \"%s\"...\n", srcDir);
continue;
}
for (i = 0; i < strlen(Buf); i ++)
if (' ' != Buf[i])
break;
if (i >= strlen(Buf))
continue;
if (!strcmp(Buf, DOTNAMES))
{ /* DOTNAME file */
printf("Analyzing directory \"%s\"...\n", srcDir);
sprintf(Buf, "%s/%s", srcDir, DOTNAMES);
if (NULL == (pDOTNames = fopen(Buf, "rt")))
{
printf("Unexpected error: Can not open file \"%s\"\n", DOTNAMES);
fclose(pls_AFR);
exit(-3);
}
NumFile = 0;
if (NumDir > 1)
{ /* obtain the corresponding digital directory name */
for (i = 0; i < NumDir; i ++)
if (!strcmp(srcDX[i], srcDir))
{
sprintf(dstDir, "%s/%08d", dstX, i);
break;
}
if (i == NumDir)
{
printf("Unexpected error: directory control failed\n");
fclose(pls_AFR);
exit(-4);
}
if (mkdir(dstDir, 0000755))
{
printf("Unexpected error: Can not create directory \"%s\"\n", dstDir);
fclose(pls_AFR);
exit(-3);
}
}
else
strcpy(dstDir, dstX);
sprintf(Buf, "%s/%s", dstDir, INDEXTMP);
if (NULL == (pINDEXhtml = fopen(Buf, "wt")))
{
printf("Unexpected error: Can not write file \"%s\"\n", INDEXTMP);
fclose(pDOTNames);
fclose(pls_AFR);
exit(-3);
}
while (!feof(pDOTNames))
{
fgets(Buf, MAXLINELEN, pDOTNames);
if (feof(pDOTNames))
break;
else
Buf[strlen(Buf) - 1] = 0;
if (ptr = strstr(Buf, "Title="))
{
fputs("<HTML>\n\n<HEAD>\n <TITLE>", pINDEXhtml);
fputs(ptr + 6, pINDEXhtml);
fputs("</TITLE>\n</HEAD>\n\n<BODY>\n\n<CENTER><H1>", pINDEXhtml);
fputs(HEADER, pINDEXhtml);
fputs("</H1></CENTER>\n\n", pINDEXhtml);
}
else if (ptr = strstr(Buf, "Name="))
{
fputs("<A HREF=\"", pINDEXhtml);
strcpy(anchor, ptr + 5);
while (1)
{
fgets(Buf, MAXLINELEN, pDOTNames);
if (feof(pDOTNames))
{
printf("Unexpected error: Incorrect format in \"%s\" file\n", DOTNAMES);
fclose(pINDEXhtml);
fclose(pDOTNames);
fclose(pls_AFR);
exit(-3);
}
else if (ptr = strstr(Buf, "Path=~/"))
{
ptr[strlen(ptr) - 1] = 0;
fputs(ptr + 7, pINDEXhtml);
fputs("\">", pINDEXhtml);
fputs(anchor, pINDEXhtml);
fputs("</A><BR>\n", pINDEXhtml);
break;
}
} /* while (1) */
} /* Title || Name */
} /* while (!feof(pDOTNames)) */
fputs("\n\n<CENTER><H1>", pINDEXhtml);
fputs(FOOTER, pINDEXhtml);
fputs("</H1></CENTER>\n\n", pINDEXhtml);
fputs("\n\n</BODY>\n\n</HTML>", pINDEXhtml);
fclose(pINDEXhtml);
fclose(pDOTNames);
} /* if (!strcmp(Buf, DOTNAMES)) */
else
{ /* common X files */
sprintf(srcFile, "%s/%s", srcDir, Buf);
printf("Processing file \"%s\"...\n", srcFile);
if (!strcmp(Buf, ".BMpath"))
{
printf("Skipping file \"%s\"...\n", srcFile);
continue;
}
if (NULL == (psrcFile = fopen(srcFile, "rt")))
{
printf("Unexpected error: Can not open file \"%s\"\n", srcFile);
fputs("\n\n</BODY>\n\n</HTML>", pINDEXhtml);
fclose(pINDEXhtml);
fclose(pDOTNames);
fclose(pls_AFR);
exit(-3);
}
strcpy(srcFX[NumFile], Buf);
sprintf(dstFX[NumFile], "%08d.htm", NumFile);
sprintf(dstFile, "%s/%s", dstDir, dstFX[NumFile ++]);
if (NumFile >= MAXFILENUM)
{
printf("Fatal error: file number in this directory exceeds %s\n", MAXFILENUM);
fclose(psrcFile);
fclose(pINDEXhtml);
fclose(pDOTNames);
fclose(pls_AFR);
exit(-3);
}
if (NULL == (pdstFile = fopen(dstFile, "wt")))
{
printf("Unexpected error: Can not write file \"%s\"\n", dstFile);
fputs("\n\n</BODY>\n\n</HTML>", pINDEXhtml);
fclose(psrcFile);
fclose(pINDEXhtml);
fclose(pDOTNames);
fclose(pls_AFR);
exit(-3);
}
fputs("<HTML>\n\n<HEAD>\n <TITLE>", pdstFile);
fputs(HEADER, pdstFile);
fputs("</TITLE>\n</HEAD>\n\n<BODY>\n\n<CENTER><H1>", pdstFile);
fputs(HEADER, pdstFile);
fputs("</H1></CENTER>\n\n", pdstFile);
while (!feof(psrcFile))
{
fgets(srcLine, MAXLINELEN, psrcFile);
if (feof(psrcFile))
break;
if ('\n' == srcLine[strlen(srcLine) - 1])
srcLine[strlen(srcLine) - 1] = ' ';
for (j = 0; srcLine[j]; j ++)
{
if (ptr = strchr(srcLine + j, '@'))
{
j = ptr - srcLine;
if (strchr(ptr, '.'))
{
if (strchr(ptr, ' ') - strchr(ptr, '.') > 0)
{
for (k = j - 1; k >= 0; k --)
if (!( (srcLine[k] >= '0' && srcLine[k] <= '9')
||(srcLine[k] >= 'A' && srcLine[k] <= 'Z')
||(srcLine[k] >= 'a' && srcLine[k] <= 'z')
|| '.' == srcLine[k]) )
break;
strcpy(Buf2, srcLine + k + 1);
sprintf(srcLine + k + 1, "mailto:%s", Buf2);
ptr += 7; /* strlen("mailto:") */
j = strchr(ptr, ' ') - srcLine - 1;
} /* End if (strchr(ptr, ' ') - strchr(ptr, '.') > 0) */
} /* End if (strchr(ptr, '.')) */
} /* End if (ptr = strchr(srcLine + j, '@')) */
} /* for (j = 0; srcLine[j]; j ++) */
for (j = Buf2[0] = 0; srcLine[j]; j ++)
{
switch (srcLine[j])
{
case '>':
strcat(Buf2, ">");
break;
case '<':
strcat(Buf2, "<");
break;
case '&':
strcat(Buf2, "&");
break;
case '"':
strcat(Buf2, """);
break;
case ' ':
strcat(Buf2, " ");
break;
case 27:
ptr = strchr(srcLine + j, 'm');
if (ptr)
j = ptr - srcLine;
break;
case 'h':
case 'H':
case 'f':
case 'F':
case 'n':
case 'N':
case 'm':
case 'M':
if (!strncasecmp(srcLine + j, "http://", 7)
|| !strncasecmp(srcLine + j, "ftp://", 6)
|| !strncasecmp(srcLine + j, "news://", 7)
|| !strncasecmp(srcLine + j, "mailto:", 7))
{
ptr = strchr(srcLine + j, ' ');
if (ptr)
{
*ptr = 0;
k = strlen(Buf2);
sprintf(Buf2 + k, "<A HREF=\"%s\">%s</A>", srcLine + j, srcLine + j + 7 * (!strncasecmp(srcLine + j, "mailto:", 7)));
*ptr = ' ';
j += ptr - (srcLine + j) - 1;
break;
}
}
/* no break here ! */
default:
Buf2[k = strlen(Buf2)] = srcLine[j];
Buf2[k + 1] = 0;
}
}
if (':' == srcLine[0])
sprintf(dstLine, "∶<I>%s</I><BR>\n", Buf2 + 1);
else if ('>' == srcLine[0])
sprintf(dstLine, "><I>%s</I><BR>\n", Buf2 + 4);
else
sprintf(dstLine, "%s<BR>\n", Buf2);
fputs(dstLine, pdstFile);
}
fputs("\n\n<CENTER><H1>", pdstFile);
fputs(FOOTER, pdstFile);
fputs("</H1></CENTER>\n\n", pdstFile);
fputs("\n\n</BODY>\n\n</HTML>", pdstFile);
fclose(pdstFile);
fclose(psrcFile);
} /* if (!strcmp(Buf, DOTNAMES)) else ... */
} /* while (!feof(pls_AFR)) */
printf("Finished creating HTML files...\n");
fclose(pls_AFR);
printf("Compressing HTML files...\n");
printf("Calling \"tar\"...\n");
sprintf(Buf, "%s/%s.html.tar", WORKDIR, srcX);
unlink(Buf);
sprintf(Buf, "tar cf %s/%s.html.tar %s", WORKDIR, srcX, dstX);
system(Buf);
printf("Cleaning working directory/data...\n");
sprintf(Buf, "rm -fr %s %ld.Xhtml", dstX, now);
system(Buf);
if (0 == chdir(dstX))
{
printf("Unexpected error: Can not erase directory \"%s\"\n", dstX);
exit(-2);
}
printf("Calling \"gzip\"...\n");
sprintf(Buf, "%s/%s.html.tar.gz", WORKDIR, srcX);
unlink(Buf);
sprintf(Buf, "gzip %s/%s.html.tar", WORKDIR, srcX);
system(Buf);
sprintf(Buf, "mv -f %s/%s.html.tar.gz %s/%s.html.tgz", WORKDIR, srcX, WORKDIR, srcX);
system(Buf);
printf("Finished Xhtml: %s.html.tgz\n", srcX);
return 0;
}
--
修改:Leeward FROM too.busy.to.com
FROM too.busy.to.com