Пример 4
/* Предварительная разметка текста для nroff */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h> /* прототип strchr() */
#include <locale.h>
FILE *fout = stdout; /* канал вывода */
/* Состояния вывода */
#define SPACE 0 /* пробелы */
#define TEXT 1 /* текст */
#define PUNCT 2 /* знаки препинания */
#define UC(c) ((unsigned char)(c))
/* Вывод строки текста из буфера */
void putstr (FILE *fp, unsigned char *s) {
/* Punct - знаки препинания, требующие приклеивания к
* концу предыдущего слова.
* PunctS - знаки, всегда требующие после себя пробела.
* PunctN - знаки, которые могут следовать за знаком
* препинания без пробела.
*/
static char Punct [] = ",:;!?.)" ;
static char PunctS[] = ",:;" ;
static char PunctN[] = " \t\"'" ;
#define is(c, set) (strchr(set, UC(c)) != NULL)
int c, state = TEXT, cprev = 'X';
while ((c = *s) != '\0') {
/* Пробелы */
if(isspace(c)) state = SPACE;
/* Знаки препинания. Пробелы перед ними игнорируются.
*/ else if(is(c, Punct)){
switch(state){
case SPACE: if(is(cprev, Punct ) && cprev==c && c != ')')
putc(' ', fp);
/* а просто пробелы - игнорировать */ break;
case PUNCT: if(is(cprev, PunctS)) putc(' ', fp); break;
}
putc(cprev = c, fp); /* выводим сам знак */
state = PUNCT;
} else {
/* Несколько пробелов сворачиваем в один */
switch(state){
case SPACE: putc(' ', fp); break;
case PUNCT: if(!is(c, PunctN)) putc(' ', fp); break;
}
putc(cprev = c, fp); /* сама буква */
state = TEXT;
if(c == '\\') putc('e', fp);
}
s++;
} /* пробелы в конце строки просто игнорируются */
putc ('\n', fp);
}
/* Обработать файл с именем name */
void proceed (char *name) {
FILE *fp;
static unsigned char inp[2048];
/* достаточно большой буфер ввода */
if (strcmp(name, "-") == 0 ) fp = stdin;
else if ((fp = fopen (name, "r")) == NULL) {
fprintf (stderr, "Cannot read %s\n", name);
return;
}
while (fgets (inp, sizeof inp, fp) != NULL) {
register unsigned char *s, *p;
int len = strlen (inp);
if (len && inp[len - 1] == '\n')
inp[--len] = '\0';
if (!*inp) {
/* .sp N - пропуск N пустых строк */
space: fprintf (fout, ".sp 1\n");
continue;
}
/* обрезать концевые пробелы */
for(p = NULL, s = inp; *s; ++s){
if (!isspace (*s)) p = s;
}
if(p) p[1] = '\0';
else goto space;
/* p указывает на последний непробел */
/* Удалить переносы слов в конце строки: перенос - это
минус, прижатый к концу слова */
if (*p == '-' && p != inp /* не в начале строки */
&& isalnum(UC(p[-1])) /* после буквы */
){ int c; *p = '\0'; /* затереть перенос */
/* Читаем продолжение слова из начала следующей строки */
while (isspace (c = getc (fp)));
ungetc (c, fp);
while ((c = getc (fp)) != '\n' && !isspace (c))
*p++ = c;
*p = '\0';
if (c != '\n' ){ /* прочли пробел */
/* вычитываем ВСЕ пробелы */
while (isspace(c = getc (fp)));
if(c != '\n') ungetc (c, fp);
}
}
/* .pp - директива начала абзаца. */
if (isspace (*inp)) {
fprintf (fout, ".pp\n");
for (s = inp; isspace (*s); s++);
putstr (fout, s);
}
else {
if (*inp == '.' || *inp == '\'')
fprintf (fout, "\\&");
putstr (fout, inp);
}
}
if( fp != stdin ) fclose (fp);
}
int main (int argc, char *argv[]) {
int i;
setlocale(LC_ALL, "");
for (i = 1; i < argc; i++)
proceed (argv[i]);
return 0; /* exit code */
}
© Copyright А. Богатырев, 1992-95
Си в UNIX
Назад | Содержание | Вперед