повышенное качество печати 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()-ом!
Организация текста в виде массива ссылок на строки или списка ссылок на строки,
а не в виде двумерного текстового поля, выгодна еще тем, что такие строки проще
переставлять, сортировать, вставлять строку в текст, удалять строку из текста. При
этом переставляются лишь указатели в линейном массиве, а сами строки никуда не копи-