Пример 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

Назад | Содержание | Вперед