Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Demon's Souls |#13| Storm King
Demon's Souls |#11| Мaneater part 2
Demon's Souls |#10| Мaneater (part 1)
Demon's Souls |#9| Heart of surprises

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Богатырев А. Весь текст 1009.15 Kb

Хрестоматия по программированию на Си в Unix

Предыдущая страница Следующая страница
1 ... 50 51 52 53 54 55 56  57 58 59 60 61 62 63 ... 87
    повышенное качество печати       ESC x 1      ESC x 0
             (near letter quality)     nlq         draft
    верхние индексы  (superscript)   ESC S 0      ESC T
    нижние индексы   (subscript)     ESC S 1      ESC T
    сжатый шрифт (17 букв/дюйм)      '\017'       '\022'
                     (condensed)
    двойная ширина букв              ESC W 1      ESC W 0
                     (expanded)
    пропорциональная печать          ESC p 1      ESC p 0
                     (proportional spacing)

Можно включить одновременно несколько из перечисленных выше  режимов.   В  каждой  из
следующих двух групп надо выбрать одно из трех:

            pitch (плотность печати)
    pica   (10 букв/дюйм)            ESC P
    elite  (12 букв/дюйм)            ESC M
    micron (15 букв/дюйм)            ESC g

            font  (шрифт)
    черновик (draft (Roman))         ESC k '\0'
    текст    (text  (Sans Serif))    ESC k '\1'
    курьер   (courier)               ESC k '\2'

Всюду выше 0 означает либо '0' либо '\0'; 1 означает либо '1' либо '\1'.  Пример:

    printf( "This is \033Gboldface\033H word\n");

А. Богатырев, 1992-95                  - 292 -                              Си в UNIX

7.30.  Составьте программу вывода набора файлов на печать, начинающую каждый  очеред-
ной  файл с новой страницы и печатающую перед каждым файлом заголовок и номер текущей
страницы. Используйте символ '\f' (form feed) для перевода листа принтера.

7.31.  Напишите программу печати текста в две колонки.  Используйте буфер для  форми-
рования  листа:  файл  читается  построчно (слишком длинные строки обрубать), сначала
заполняется левая половина листа (буфера), затем правая. Когда лист полностью  запол-
нен  или  файл  кончился - выдать лист построчно, расписать буфер пробелами (очистить
лист) и повторить заполнение очередного листа. Указание: размеры листа должны переда-
ваться как аргументы main(), для буфера используйте двумерный массив букв, память для
него заказывайте динамически.  Усложнение: не обрубайте, а переносите слишком длинные
строки (строка может потребовать даже переноса с листа на лист).

    /* ПРОГРАММА ПЕЧАТИ В ДВЕ ПОЛОСЫ: pr.c */
    #include 
    #include 
    #define YES 1
    #define NO  0
    #define FORMFEED '\f'
    #define LINEFEED '\n'

    extern char *malloc(unsigned);
    extern char *strchr(char *, char);
    void untab(register char *s);
    void resetsheet( void );
    void addsheet( char *s, FILE *fpout );
    void flushsheet( FILE *fpout );
    void printline( int y, char *s, char *attr,
                    FILE *fpout );
    void doattr( register char *abuf,
                 register char *vbuf );
    void printcopy( FILE *fpin, FILE *fpout );
    void main(void);
    char *strdup (const char *s){
      char *p = malloc(strlen(s)+1); strcpy(p,s); return p;

      /* return strcpy((char *) malloc(strlen(s)+1), s); */
    }

    /* ... текст функции untab() ... */

    int Sline;       /* строка на листе            */
    int Shalf;       /* половина листа             */
    int npage;       /* номер страницы             */
    int startpage = 1;
                /* печать начиная с 1ой страницы   */
    int fline;       /* номер строки файла         */
    int topline = 0; /* смещение до начала листа   */
    int halfwidth;   /* ширина полулиста           */
    int twocolumns = YES;   /* в две колонки ?     */
    int lshift, rshift = 1; /* поля слева и справа */
    typedef unsigned short ushort;
    int COLS  = 128; /* ширина листа (букв)        */
    int LINES =  66; /* длина листа (строк)        */
    ushort *mem;     /* буфер листа                */
    #define AT(x,y)  mem[ (x) + (y) * COLS ]

    /* Выделить буфер под лист и зачистить его */
    void resetsheet ( void ){
       register x;
       if( mem == NULL ){ /* выделить память */

А. Богатырев, 1992-95                  - 293 -                              Си в UNIX

           if ((mem = (ushort *)
             malloc (COLS * LINES * sizeof(ushort)))
             == NULL ){
             fprintf(stderr, "Out of memory.\n"); exit(1);
           }
       }
       /* очистить */
       for( x= COLS * LINES - 1 ; x >= 0 ; x-- )
               mem[x] = ' ' & 0xFF;
       halfwidth = (twocolumns ? COLS/2 : COLS )
                   - (lshift + rshift );
       Sline = topline; Shalf = 0;
    }

    #define NEXT_HALF \
       if( twocolumns == YES && Shalf == 0 ){         \
           /* закрыть данную половину листа */        \
           Shalf = 1; /* перейти к новой половине */  \
           Sline = topline;                           \
       } else                                         \
           flushsheet(fpout)   /* напечатать лист */

    /* Записать строку в лист */
    void addsheet ( char *s, FILE *fpout )
    {
       register x, y;
       register i;
       char *rest = NULL;
       int wrap = NO;
    /* YES когда идет перенос слишком длинной строки */

       /* в какое место поместить строку? */
       x = (Shalf == 0 ? 0 : COLS/2) + lshift;
       y = Sline;

       i = 0;     /* позиция в строке s */
       while (*s) {
           if( *s == '\f' ){
               /* вынужденный form feed */
               rest = strdup( s+1 ); /* остаток строки */
               NEXT_HALF;
               if( *rest ) addsheet(rest, fpout);
               free( rest );
               return;
           }
           if( i >= halfwidth ){
           /* перенести длинную строку */
               wrap = YES;
               rest = strdup(s);
               break;
           }
           /* Обработка выделений текста */
           if( s[1] == '\b' ){
               while( s[1] == '\b' ){
                  AT(x, y) = (s[0] << 8) | (s[2] & 0xFF);
                  /* overstrike */
                  s += 2;
               }
               s++; x++; i++;
           } else {
               AT (x, y) = *s++ & 0xFF;

А. Богатырев, 1992-95                  - 294 -                              Си в UNIX

               x++; i++;
           }
       }
       /* Увеличить строку/половину_листа */
       Sline++;
       if (Sline == LINES) { /* полулист заполнен */
           NEXT_HALF;      }
       if( wrap && rest )  { /* дописать остаток строки */
           addsheet(rest, fpout); free(rest);
       }
    }
    int again;      /* нужна ли повторная надпечатка? */
    /* Напечатать заполненный лист */
    void flushsheet ( FILE *fpout ){
       register x, y, xlast;
       char *s, *p;
       static char outbuf[BUFSIZ], attr[BUFSIZ];
       /* attr - буфер под атрибуты выделений */
       ushort c;

       if( npage >= startpage )
         for (y = 0; y < LINES; y++) {
            /* обрезать концевые пробелы */
            for (xlast = (-1), x = COLS - 1; x >= 0; x--)
               if (AT (x, y) != ' ') { xlast = x; break; }
            again = NO; s = outbuf;  p = attr;
            for (x = 0; x <= xlast; x++){
               c = AT(x, y);
               *s++ = c & 0xFF;

               /* имеет атрибуты ? */
               c >>= 8; c &= 0xFF;
               *p++ = c ? c : ' ';
               if( c ) again = YES;
            }
            *s = '\0'; *p = '\0';
            printline(y, outbuf, attr, fpout);
         }
       npage++;        /* next page */
       resetsheet();   /* зачистить новый лист */
    }

    /* Напечатать одну строку листа */
    void printline ( int y, char *s, char *attr,
                    FILE *fpout ){
       register x;
       if( again ){
           doattr(attr, s); fprintf(fpout, "%s\r", attr );
       }
       fprintf(fpout, "%s", s);
       /* перевод листа или строки */
       fputc( y == LINES-1 ? FORMFEED : LINEFEED, fpout );
    }

    /* Проверить - нет ли атрибутов выделений */
    void doattr ( register char *abuf,
                  register char *vbuf ){
       for(; *abuf; abuf++, vbuf++ )
          if( !strchr(" _-!|\177", *abuf))
              *abuf = *vbuf;
    }

А. Богатырев, 1992-95                  - 295 -                              Си в UNIX

    /* Копирование файла на принтер */
    void printcopy ( FILE *fpin, FILE *fpout )
    {
       char inbuf[BUFSIZ];

       npage = 1; /* первая страница имеет номер 1 */
       fline = 0; /* текущая строка файла - 0      */

       resetsheet();  /* зачистить буфер листа */
       while( fgets(inbuf, sizeof inbuf - 1, fpin )
               != NULL ){
               register l = strlen( inbuf );
               if( l && inbuf[l-1] == '\n' )
                        inbuf[--l] =  '\0' ;
               fline++;
               untab   ( inbuf );
               addsheet( inbuf, fpout );
       }
       if( !(Sline == topline && Shalf == 0))
       /* если страница не была только что зачищена ... */
             flushsheet(fpout);
       fprintf(stderr, "%d строк, %d листов.\n",
                        fline,    npage-1);
    }
    /* Вызов: pr < файл > /dev/lp */
    void main (){ printcopy(stdin, stdout); }

Файл-принтер имеет в UNIX имя /dev/lp или подобное ему, а в MS DOS - имя prn.

7.32.  Напишите программу, которая построчно считывает  небольшой  файл  в  память  и
печатает  строки  в  обратном  порядке.   Указание: используйте динамическую память -
функции malloc() и strcpy().
     Объясним, почему желательно пользоваться динамической памятью.  Пусть мы  знаем,
что строки имеют максимальную длину 80 символов и максимальное количество строк равно
50.  Мы могли бы хранить текст в двумерном массиве:

    char text[50][80];

занимающем 50*80 = 4000 байт памяти.  Пусть теперь  оказалось,  что  строки  файла  в
действительности имеют длину по 10 букв. Мы

    используем           50 * (10 + 1) =  550 байт
    не используем 4000 - 50 * (10 + 1) = 3450 байт

(+1 нужен для символа '\0' на конце строки).
     Пусть мы теперь пишем

    char *text[50]; int i=0;

и при чтении очередной строки сохраняем ее так:

    char buffer[81], *malloc(),  *gets();
    while( gets(buffer) != NULL ){
      text[i] = (char *) malloc(strlen(buffer)+1);
      /* +1 для хранения \0, который не учтен strlen-ом */
      strcpy(text[i++], buffer);
    }

то есть заказываем ровно столько памяти, сколько надо для хранения строки и ни байтом
больше. Здесь мы (если sizeof(char *)==4) используем

А. Богатырев, 1992-95                  - 296 -                              Си в UNIX

               50 * 4 +  50 * (10 + 1 + 4) = 950 байт
    массив указателей + заказанная malloc память

(+4 - служебная информация malloc), но зато у нас не остается неиспользуемой  памяти.
Преимуществом  выделения  памяти в виде массива является то, что эта память выделится
ГАРАНТИРОВАННО, тогда как malloc()-у может не хватить памяти (если мы ее прежде очень
много  захватывали  и  не освобождали free()).  Если malloc не может выделить участок
памяти требуемого размера, он возвращает значение NULL:

    if((text[i] = malloc(....)) == NULL)
    { fprintf(stderr, "Мало памяти\n"); break; }

Распечатка строк:

    for(--i; i >= 0; i-- ){
            printf("%s\n", text[i]);
            free( text[i] );
    }

Функция free(ptr) "освобождает"[*] отведенную ранее malloc()ом или  calloc()ом  область
памяти по адресу ptr так, что при новых вызовах malloc() эта область может быть пере-
использована.  Данные в освобожденной  памяти  ПОРТЯТСЯ  после  free().  Ошибочно  (и
опасно) освобождать память, которая НЕ БЫЛА отведена malloc()-ом!
     Организация текста в виде массива ссылок на строки или списка ссылок на  строки,
а  не  в  виде  двумерного  текстового  поля, выгодна еще тем, что такие строки проще
переставлять, сортировать, вставлять строку в текст, удалять строку из  текста.   При
этом  переставляются лишь указатели в линейном массиве, а сами строки никуда не копи-
Предыдущая страница Следующая страница
1 ... 50 51 52 53 54 55 56  57 58 59 60 61 62 63 ... 87
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 

Реклама