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

}

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

Используются технологии uCoz