LaTeX 写作的两个辅助工具:统计中文字数和关闭Acrobat中的PDF文档

LaTeX 没有像 Word 那样自带中文字数统计功能,加上 LaTeX 源文件中有许多控制字符,不能通过文件大小获知其中有多少汉字。为此我用C写了一个统计中文字数的小工具,名为 cwc ,即 chinese word counter。这个程序只有 count_files() 函数使用了 Windows API,稍作修改就能移植到 Linux/Unix 下。


#include <stdio.h>
#include <wchar.h>
#include <windows.h>
int total = 0; // total chinese characters

// UNICODE version word counter
void word_count_u(FILE* pf)
{
int w = 0, b = 2;
wint_t c;

while((c = getwc(pf)) != WEOF) {
b += 2; // byte count
if (c > 127) {//中文字符
w++;//char count
}
}

printf("%10d \t %10d\n", w, b);
total += w;
}

//word counter
void word_count(const char* file)
{
int w = 0, b = 0;
int c;
int unicode = 0;

FILE *pf = fopen(file, "rb");
if (NULL == pf){
return;
}
printf ("%20s : ", file);

// 判断是否为 UNICODE 文件
if ((c = getc(pf)) == 0xff) {
int cc;
if ((cc = getc(pf)) == 0xfe) {
unicode = 1;
printf("UNICODE");
word_count_u(pf);
}
else {
fseek(pf, 0, SEEK_SET);
}
}
else {
ungetc(c, pf);
}

if (!unicode) {
printf(" ");
while((c = getc(pf)) != EOF) {
b++; // byte count
if (c > 127) { // 中文字符
w++; // char count
b++; // 每个中文字符占两字节
if ((c = getc(pf)) == EOF)
break;
}
}

printf("%10d \t %10d\n", w, b);
total += w;
}
fclose(pf);
}

void count_files(const char* file)
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind = FindFirstFile(file, &FindFileData);

if (INVALID_HANDLE_VALUE == hFind) {
fprintf(stderr, "Can't find %s\n", file);
return ;
}

do {
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
continue;
}
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// do nothing
}
else {
word_count(FindFileData.cFileName);
}
} while (FindNextFile(hFind, &FindFileData));

FindClose(hFind);
}

int main(int argc, char* argv[])
{
if (1 == argc) {
// default: count all .tex and .txt files in current dir
count_files("*.tex");
count_files("*.txt");
}
else {
// get filenames from command line arguments
while (--argc > 0) {
count_files(argv[argc]);
}
}
printf(" Total : %d", total);
return 0;
}

另外一个常见的问题是,用 dvipdfm 生成 PDF 文件时,经常忘了在 Acrobat 中关闭这个文件,而导致出现以下错误提示:

E:\Projects\SlideWindowReport>dvipdfm SlideWindow

SlideWindow.dvi -> SlideWindow.pdf

Unable to open SlideWindow.pdf


Output file removed.

为此我写了一个专门用来关闭 Acrobat 中的 PDF 文件的小工具,名为 closepdf,原理是通过 DDE 告诉 Acrobat 关闭某个 PDF 文件。这个小工具的灵感来自 WinEdt 的自动关闭功能(我跟踪它的宏代码得知如何用 DDE 控制 Acrobat),代码改自 MSDN 的一篇文章。我完全不懂 DDE,不过这不妨碍程序的正常工作:)

有了这个小工具,我就可以写一个 batch file 来编译生成并阅读 PDF 文件:

rem this is m.bat
latex %1
latex %1
closepdf %1.pdf
dvipdfm %1 %2 %3 %4 %5
start %1.pdf

代码如下:
// close the user specified pdf file in Acrobat Reader

// ref. Microsoft Knowledge Base Article - 279721
// HOWTO: Use Dynamic Data Exchange (DDE) with Word and Excel from Visual C++

// modified by Solstice 2004/01/2

#define WIN32_LEAN_AND_MEAN// Exclude rarely-used stuff from Windows headers
#define STRICT

#include <windows.h>
#include <ddeml.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

HDDEDATA CALLBACK DdeCallback(
UINT uType, // Transaction type.
UINT uFmt, // Clipboard data format.
HCONV hconv, // Handle to the conversation.
HSZ hsz1, // Handle to a string.
HSZ hsz2, // Handle to a string.
HDDEDATA hdata, // Handle to a global memory object.
DWORD dwData1, // Transaction-specific data.
DWORD dwData2) // Transaction-specific data.
{
return 0;
}

void DDEExecute(DWORD idInst, HCONV hConv, char* szCommand)
{
HDDEDATA hData = DdeCreateDataHandle(idInst, (LPBYTE)szCommand,
lstrlen(szCommand)+1, 0, NULL, CF_TEXT, 0);
if (hData==NULL) {
printf("Command failed: %s\n", szCommand);
}
else {
DdeClientTransaction((LPBYTE)hData, 0xFFFFFFFF, hConv, 0L, 0,
XTYP_EXECUTE, TIMEOUT_ASYNC, NULL);
}
}

void DDERequest(DWORD idInst, HCONV hConv, char* szItem, char* sDesc)
{
HSZ hszItem = DdeCreateStringHandle(idInst, szItem, 0);
HDDEDATA hData = DdeClientTransaction(NULL,0,hConv,hszItem,CF_TEXT,
XTYP_REQUEST,5000 , NULL);
if (hData == NULL)
{
printf("Request failed: %s\n", szItem);
}
else
{
char szResult[255];
DdeGetData(hData, (unsigned char *)szResult, 255, 0);
printf("%s%s\n", sDesc, szResult);
}
}

void DDEPoke(DWORD idInst, HCONV hConv, char* szItem, char* szData)
{
HSZ hszItem = DdeCreateStringHandle(idInst, szItem, 0);
DdeClientTransaction((LPBYTE)szData, (DWORD)(lstrlen(szData)+1),
hConv, hszItem, CF_TEXT,
XTYP_POKE, 3000, NULL);
DdeFreeStringHandle(idInst, hszItem);
}

int get_error(const char* filename)
{
HANDLE hFile = CreateFile(filename,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);

if (INVALID_HANDLE_VALUE == hFile) {
return GetLastError();
} else {
CloseHandle(hFile);
return 0;
}
}

bool is_file_locked(const char* filename)
{
return (get_error(filename) == 32);
}

bool is_file_exists(const char* filename)
{
return (get_error(filename) != 2);
}

int main(int argc, char* argv[])
{
char szApp[] = "acroview";
char szTopic[] = "control";
char szCloseAll[] = "[CloseAllDocs()]";
char full_file_name[MAX_PATH];
const char* file_to_close = argv[1];

if (argc == 1) {
// close all pdf files
} else { // close the specified file
if (!is_file_exists(file_to_close)) {
printf("%s doesn't exists.\n", file_to_close);
return 1;
}
if (is_file_locked(file_to_close)) {
printf("%s is open, trying to close it...\n", file_to_close);
} else {
printf("%s is closed.\n", file_to_close);
return 0;
}
assert (GetFullPathName(
file_to_close,
sizeof(full_file_name),
full_file_name,
NULL
) > 0);
//printf("Full name : \"%s\"\n", full_file_name);
}

//[DocOpen(""%P\%N.pdf"")]
//[DocClose(""%P\%N.pdf"")]

//DDE Initialization
DWORD idInst=0;
UINT iReturn;
iReturn = DdeInitialize(&idInst, (PFNCALLBACK)DdeCallback,
APPCLASS_STANDARD | APPCMD_CLIENTONLY, 0 );
if (iReturn!=DMLERR_NO_ERROR)
{
printf("DDE Initialization Failed: 0x%04x\n", iReturn);
Sleep(1500);
return 0;
}

//DDE Connect to Server using given AppName and topic.
HSZ hszApp, hszTopic;
HCONV hConv;
hszApp = DdeCreateStringHandle(idInst, szApp, 0);
hszTopic = DdeCreateStringHandle(idInst, szTopic, 0);
hConv = DdeConnect(idInst, hszApp, hszTopic, NULL);
DdeFreeStringHandle(idInst, hszApp);
DdeFreeStringHandle(idInst, hszTopic);
if (hConv == NULL)
{
printf("DDE Connection Failed.\n");
Sleep(500); DdeUninitialize(idInst);
return 0;
}
else
{
printf("DDE Connection to Acrobat Reader succeed.\n");
Sleep(50);
}

if (argc == 1) {
// close all pdf files
//Execute commands/requests specific to the DDE Server.
DDEExecute(idInst, hConv, szCloseAll);
printf("Closing all PDF documents...\n");
Sleep(50);
} else { // close the specified file
char cmd_buf[MAX_PATH + 100];
//[DocOpen(""%P\%N.pdf"")]
//[DocClose(""%P\%N.pdf"")]
printf("Closing %s \n", full_file_name);
snprintf(cmd_buf, sizeof(cmd_buf), "[DocOpen(\"%s\")]", full_file_name);
DDEExecute(idInst, hConv, cmd_buf);
Sleep(50);
snprintf(cmd_buf, sizeof(cmd_buf), "[DocClose(\"%s\")]", full_file_name);
DDEExecute(idInst, hConv, cmd_buf);
Sleep(50);
}

//DDE Disconnect and Uninitialize.
DdeDisconnect(hConv);
DdeUninitialize(idInst);

if (argc == 1) {
// close all pdf files
return (0);
}

for (int i = 0; i < 5; ++i) {
Sleep(100);
if (!is_file_locked(file_to_close))
break;
}
if (!is_file_locked(file_to_close)) {
printf("%s is closed.\n", file_to_close);
return 0;
} else {
printf("%s is still open.\n", file_to_close);
return 1;
}
}

你可能感兴趣的:(C++,c,windows,C#,Excel)