/* /bin/cc -M2 -Ml -DMATCHONLY -LARGE dosfs.c match.c -o dosfs * Копирование файлов с дискеты, записанной в MS DOS, в UNIX. * Предполагается, что ваша UNIX-машина имеет соответствующий драйвер * для чтения дискет, сформатированных на IBM PC. * match.c - файл, содержащий текст функции match(). */ #include <stdio.h> #include <fcntl.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> extern char *malloc(); /* выделитель памяти */ extern char *strrchr(); /* поиск последнего вхождения буквы */ extern long lseek(); void readBoot(), readFAT(), readRootDir(), main(), line(), getFile(), doDirectory(), mkname(), enterDir(), countFree(), traceclu(); int fd; /* дескриптор файла - дисковода */ FILE *mapfp; /* файл трассировки */ int trace = 0; /* трассировка пока выключена */ int ask = 1; /* спрашивать ли подтверждение на перезапись файлов */ int dironly = 0; /* 1: только показывать имена, файлы не скидывать */ typedef unsigned char uchar; /*typedef unsigned short ushort; Есть в sys/types.h */ /* Формат сектора загрузки */ struct boot { char jmp[3]; /* команда jmp */ char label[8]; /* название системы */ char bfs[2]; /* размер boot-сектора */ uchar sectorsPerCluster; /* число секторов в кластере */ char fatoff[2]; /* смещение до начала FAT */ uchar copies; /* число копий FAT */ char dirsize[2]; /* число записей в корневом каталоге */ char sectors[2]; /* размер дискеты в секторах */ uchar desc; /* описатель типа дискеты */ char FATsize[2]; /* размер FAT в секторах */ char sectorsPerTrack[2]; /* число секторов на трек */ char sides[2]; /* число сторон (1, 2) */ char hidden[2]; /* число спрятанных секторов */ } *boot; #define SECTOR 512 /* Размер сектора в байтах */ int CLU; /* Размер кластера в байтах */ int SPC; /* Размер кластера в секторах */ int SECT; /* Число секторов на дискете */ long capacity; /* емкость дискеты в байтах */ ushort MAXCLU; /* максимальный номер кластера + 1 */ int NDIR; /* Число слотов в корневом каталоге */ int DIRSIZE; /* Длина корневого каталога в байтах */ int ENTRperCLUSTER; /* Количество слотов в одном кластере каталога */ int SPF; /* Размер FAT в секторах */ int FATSIZE; /* Размер FAT в байтах */ int FATSTART; /* Смещение до FAT в байтах */ int NFAT; /* Количество копий FAT */ uchar DESC; /* Описатель типа дискеты */ int DATACLU; /* Начало области данных (номер физич. кластера) */ int bit16 = 0; /* 1 если FAT использует 16-битные поля, а не 12 */ /* Преобразование char[] в integer */ #define INT(s) ( * (short *)s) #define LONG(s) ( * (long *)s) /* Формат одной записи каталога. */ struct dir{ char name[8]; /* имя файла */ char ext[3]; /* расширение (суффикс) */ uchar attrib; /* атрибуты файла */ char unused[10]; char creat_time[2]; /* время создания */ char creat_date[2]; /* дата создания */ char firstCluster[2]; /* начальный кластер */ char size[4]; /* размер в байтах */ }; #define isdir(attr) (attr & 0x10) /* Является ли каталогом ? */ #define islabel(attr) (attr & 0x08) /* Метка тома ? */ #define eq(s1, s2) (!strcmp(s1, s2)) /* сравнение строк на == */ struct dir *droot; /* Содержимое корневого каталога */ char *FAT1; /* File Allocation Table, копия 1 */ char *FAT2; /* копия 2 */ char cwd[256] = ""; /* Текущий каталог в DOS. "" - корневой */ char *root = "/tmp"; /* Каталог в UNIX, куда копируются файлы */ char *pattern = NULL; /* шаблон базового имени */ char *dirpattern; /* каталог (не шаблон) */ char newname[256]; /* буфер дла генерации имен */ char cluster[4098]; /* буфер для чтения кластера */ /* Чтение n байт по адресу s */ Read(fd, s, n) char *s; { int nn = read(fd, s, n); if(nn != n ){ fprintf(stderr, "Ошибка чтения: %d вместо %d\n", nn, n); perror( "read" ); exit(1); } return nn; } /* Позиционирование головок */ long Lseek(fd, off, how) long off; { long offf; if((offf = lseek(fd, off, how)) < 0){ fprintf(stderr, "Ошибка lseek(%ld,%d)\n", off, how); } return offf; } /* Отведение памяти и ее зачистка */ char *Malloc(n) unsigned n;{ char *ptr = malloc(n); register unsigned i; if( !ptr){ fprintf(stderr, "Не могу malloc(%u)\n", n ); exit(2); } for(i=0; i < n ; i++ ) ptr[i] = 0; /* Можно было бы использовать ptr = calloc(1,n); эта функция * как раз отводит и очищает память */ return ptr; } /* Нарисовать горизонтальную черту */ void line(c) char c;{ register i; for(i=0; i < 78; i++) putchar(c); putchar('\n'); } /* Обработка псевдо-имен устройств. Используются имена для XENIX */ char *drive(name) char *name; { if( eq(name, "360")) return "/dev/fd048ds9"; if( eq(name, "720")) return "/dev/fd096ds9"; if( eq(name, "1.2")) return "/dev/fd096ds15"; return name; } /* Создать каталог */ char command[512]; /* буфер дла формирования команд */ mkdir(name, mode) char *name; { int retcode; struct stat st; if( stat(name, &st) >= 0 && (st.st_mode & S_IFMT) == S_IFDIR ) return 0; /* уже есть */ sprintf(command, "mkdir \"%s\"", name ); retcode = system(command); /* выполнить команду, записанную в command */ chmod(name, mode & 0777); /* установить коды доступа */ return retcode; /* 0 - успешно */ } /* Открыть файл, создавая (если надо) недостаюшие каталоги */ FILE *fmdopen(name, mode) char *name, *mode; { extern errno; char *s; FILE *fp; if( fp = fopen(name, mode)) return fp; /* OK */ /* иначе файл не смог создаться */ /* if( errno != ENOENT ) return NULL; /* из-за недостатка прав */ /* Пробуем создать все каталоги по пути к файлу */ if((s = strrchr(name, '/' )) == NULL ) return NULL; *s = '\0'; md(name); *s = '/'; return fopen(name, mode); } /* Рекурсивный mkdir */ md(path) char *path; { struct stat st; char *s; int code; if( !*path) return 0; /* корневой каталог "/" */ if( stat(path, &st) >= 0 ){ /* существует */ if((st.st_mode & S_IFMT) == S_IFDIR) return 0; /* OK */ printf( "%s - не каталог\n", path ); return 1; /* FAIL */ } if( s = strrchr(path, '/')){ *s = '\0'; code = md(path); *s = '/'; if( code ) return code; /* Облом */ } sprintf(command, "mkdir \"%s\"", path ); return system(command); /* 0 если OK */ } /* Сконструировать имя файла в стиле UNIX. * В MS DOS все буквы в именах - большие */ void mkname( res, n, e ) char *res, *n, *e; { /* res - результат, n - имя, e - суффикс */ register i; char *start = res; if( n[0] == 0x05 ) n[0] = 0xE5; /* подставной символ */ for(i=0; i < 8 && n[i] && n[i] != ' ' ; i++) *res++ = n[i]; if( e[0] != ' ') *res++ = '.'; for(i=0; i < 3 && e[i] && e[i] != ' ' ; i++) *res++ = e[i]; *res = '\0'; while( *start ){ if( isalpha(*start) && isupper(*start)) *start = tolower(*start); start++; } } /* ------------------------------------------------------- */ /* Получить запись из FAT для кластера clu */ ushort numCluster(clu) ushort clu; { ushort n; if( clu >= MAXCLU ) printf( "Слишком большой номер кластера %03X >= %03X\n", clu, MAXCLU ); if( bit16 ){ /* 16 бит на номер кластера */ n = INT( &FAT1[ 2*clu ]); n &= 0xFFFF; return n; } /* иначе 12 бит на номер кластера */ n = clu + clu/2 ; n = INT( &FAT1[n] ); if( clu % 2 ){ /* нечетный */ n >>= 4; } n &= 0xFFF; return n; } /* Узнать следующий кластер файла. 0 если последний */ ushort nextCluster(clu) ushort clu; { clu = numCluster(clu); if( clu >= (bit16 ? 0xFFF8 : 0xFF8 )) return 0; /* EOF */ return clu; } /* Прочесть кластер и сохранить его в файле и буфере */ getCluster(clu, fp, size, buffer) ushort clu; /* логический кластер (2..) */ FILE *fp; /* файл для спасения */ long size; /* осталось дописать */ char *buffer; /* буфер для кластера */ { long offset; int rd, howmuchtoread; if( size <= 0L ){ printf( "CLUSTER %03X лишний\n", clu ); exit(3); } /* Вычислить смещение. Кластеры нумеруются начиная с #2 */ offset = (clu - 2 + DATACLU) * (long) CLU; Lseek(fd, offset, 0); /* Сколько байт прочесть ? */ howmuchtoread = (size > CLU) ? CLU : size; rd = Read(fd, buffer, howmuchtoread); if( fp != NULL ) fwrite(buffer, 1, rd, fp); return ( rd < 0 ) ? 0 : rd; } /* ----------------------------------------------------------------- * dosfs -rPATH файлы скидываются в каталог PATH, а не в /tmp * dosfs ... "шаблон" сбрасываются только файлы с подходящими * именами, например: * dosfs 1.2 "/*.c" *.c из корня дискеты * dosfs 1.2 "/dir1/*.c" *.c из каталога /dir1 * dosfs 1.2 "*.c" *.c из всех каталогов * dosfs -d только просмотр каталогов, без сброса файлов * Пример: dosfs -qr. 360 */ void main(argc, argv) char *argv[]; { if( argc < 2 ) goto usage; if( *argv[1] == '-' ){ /* разбор ключей */ char *keys = &argv[1][1]; while(*keys){ switch(*keys){ case 't': /* включить трассировку */ trace++; if((mapfp = fopen( ".Map", "w" )) == NULL ) trace = 0; break; case 'q': /* без запросов (quiet) */ ask = 0; break; case 'r': /* переназначить root */ root = keys+1; goto breakwhile; case 'd': /* dosfs -d == команда dir */ dironly++; break; } keys++; } breakwhile: argc--; argv++; } if( argc < 2 ) goto usage; if( pattern = argv[2] ){ /* может быть NULL */ char *s = strrchr(pattern, '/'); if(s){ /* PATH/PATTERN */ dirpattern = pattern; /* PATH */ *s = '\0'; pattern = s+1; /* PATTERN */ }else{ /* просто PATTERN */ dirpattern = NULL; } } setbuf(stdout, NULL); /* отменить буферизацию */ readBoot(drive(argv[1])); readFAT(); countFree(); readRootDir(); exit(0); usage: printf( "Вызов: dosfs [-dqtrDIR] устройство [\"шаблон\"]\n" ); exit(4); } /* Прочесть boot-sector, вычислить разные параметры дискеты */ void readBoot(dsk) char *dsk; { char BOOT[SECTOR]; int skips, sides; if((fd = open( dsk, O_RDONLY)) < 0 ){ fprintf(stderr, "Не могу читать %s\n", dsk); exit(5); } /* нулевой сектор дискеты - boot */ Read(fd, BOOT, SECTOR); boot = (struct boot *) BOOT; line('-'); printf( "Сформатировано \"%8.8s\"\n", boot->label ); printf( "Размер boot-сектора %d байт\n", INT(boot->bfs)); printf( "Кластер содержит %d секторов\n", SPC = boot->sectorsPerCluster ); printf( "Дискета содержит %d секторов ", SECT = INT(boot->sectors)); capacity = SECT * (long) SECTOR; printf( "(%ld KB)\n", capacity / 1024L ); printf( "На треке %d секторов\n", INT(boot->sectorsPerTrack)); sides = INT(boot->sides); printf( "Диск имеет %d сторон%c\n\n", sides, sides==1? 'у':'ы'); printf( "Смещение до FAT %d сектор\n", skips = INT(boot->fatoff)); printf( "Имеется %d копии FAT\n", NFAT = boot->copies ); printf( "FAT занимает %d секторов\n\n", SPF = INT(boot->FATsize)); printf( "Корневой каталог содержит %d записей\n\n", NDIR = INT(boot->dirsize)); printf( "Описатель дискеты = %02X\t(", DESC = boot->desc ); switch( DESC ){ case 0xFF: printf( "double sided, 8 sectors per track" ); break; case 0xFE: printf( "single sided, 8 sectors per track" ); break; case 0xFD: printf( "double sided, 9 sectors per track" ); break; case 0xFC: printf( "single sided, 9 sectors per track" ); break; case 0xF9: printf( "double sided, 15 sectors per track"); break; case 0xF8: printf( "Winchester" ); bit16++; break; default: printf( "неизвестный тип" ); break; } printf( ")\n"); printf( "На диске %d спрятанных секторов\n", INT(boot->hidden)); /* Вычислить характеристики */ CLU = SECTOR * SPC; /* размер кластера в байтах */ FATSIZE = SECTOR * SPF; /* длина FAT в байтах */ FATSTART = SECTOR * skips; /* смещение в байтах до FAT */ /* длина корневого каталога в байтах */ DIRSIZE = NDIR * sizeof(struct dir); /* физический номер первого кластера данных */ DATACLU = ((long) FATSTART + (long) FATSIZE * NFAT + (long) DIRSIZE ) / CLU; printf( "Первый кластер данных (физ.) = %d\n", DATACLU ); /* число записей каталога в кластере */ ENTRperCLUSTER = CLU / sizeof(struct dir); /* число секторов для данных */ MAXCLU = (SECT - DATACLU * SPC); /* число кластеров для данных */ MAXCLU = MAXCLU / SPC; /* логические номера кластеров идут с #2 */ MAXCLU += 2; } /* Прочесть File Allocation Table (таблицу размещения файлов) */ void readFAT(){ register int i; FAT1 = Malloc(FATSIZE); Lseek(fd, (long) FATSTART, 0); Read(fd, FAT1, FATSIZE); if(NFAT > 1){ FAT2 = Malloc(FATSIZE); Read(fd, FAT2, FATSIZE); /* Сравнить копии FAT */ for(i=0; i < FATSIZE; i++ ) if(FAT1[i] != FAT2[i]){ printf( "копии FAT различаются в %d/%d\n", i, FATSIZE ); break; } free( FAT2 ); } if( DESC != FAT1[0] ) printf( "У FAT другой описатель: %02X\n", FAT1[0] & 0xFF ); } /* Прочесть корневой каталог дискеты. * Он расположен сразу же после копий FAT */ void readRootDir(){ if( DIRSIZE % SECTOR ) printf( "Размер каталога не кратен сектору\n" ); Lseek(fd, (long)FATSTART + (long)FATSIZE * NFAT, 0); droot = (struct dir *) Malloc(DIRSIZE); Read(fd, droot, DIRSIZE ); /* NDIR должно быть 112 для 360K и 720K * 224 для 1.2 Mb */ if( !dironly ) mkdir( root, 0755 ); line('-'); doDirectory(0, NDIR, droot); } /* Обработать каталог (напечатать, спасти файлы, обойти подкаталоги) */ #define PRINT \ for(j=0; j < level; j++ ) printf( " " ); /* отступ */ \ printf( "%02d\t%s/%-14s %12ld %s\n", \ strt + i, \ cwd, \ basename, \ size, \ isdir(dd[i].attrib) ? "<DIR>" : \ islabel(dd[i].attrib) ? "<LAB>" : "" ) void doDirectory(strt, entries, dd) struct dir dd[]; { register i, j; char basename[40]; static int level = 0; int need_to_get; /* надо ли сбрасывать */ /* line('-'); */ for(i=0; i < entries; i++ ){ uchar c; long size; if((c = *dd[i].name) == 0xE5 || !c) continue; /* файл стерт (дыра) */ mkname(basename, dd[i].name, dd[i].ext); size = LONG(dd[i].size); /* размер файла */ /* проверить шаблон имени, если нужно */ if( !pattern || /* pattern задан и */ ( (!dirpattern || eq(cwd, dirpattern)) && match(basename, pattern) ) ){ PRINT; need_to_get = !dironly; } else need_to_get = 0; if(isdir(dd[i].attrib)){ /* себя и родителя проигнорировать */ if( eq(basename, "." ) || eq(basename, "..")) continue; level++; /* У каталогов почему-то size == 0 */ enterDir( basename, INT(dd[i].firstCluster), need_to_get); level--; } else if( islabel(dd[i].attrib)){ printf( "Volume label:%11.11s\n", dd[i].name ); } else if( need_to_get ) getFile ( basename, INT(dd[i].firstCluster), size); } /* line('#'); */ } /* Прочесть файл в UNIX-ную файловую систему */ void getFile(name, clu, size) char *name; /* имя файла */ ushort clu; /* начальный кластер */ long size; /* размер */ { FILE *fp; /* файл куда сохранять */ struct stat st; ushort nclu = 0;/* порядковый номер кластера */ sprintf(newname, "%s%s/%s", root, cwd, name ); if( ask && stat(newname, &st) >= 0 ){ char answer[30]; fprintf(stderr, "%s уже существует, перезаписать? ", newname); gets(answer); if( *answer != 'y' ) return; fprintf( stderr, "\tOK\n" ); } if((fp = fmdopen( newname, "w" )) == NULL){ printf( "Не могу создать %s\n", newname ); return; } if( trace ) fprintf( mapfp, "\n%s/%s:", cwd, name ); while( clu ){ if( trace ) traceclu(nclu++, clu); size -= getCluster(clu, fp, size, cluster); clu = nextCluster(clu); } fclose(fp); } /* Обработать подкаталог */ void enterDir(name, clu, create) char *name; /* имя */ ushort clu; /* начальный кластер */ { char *tail, *myCluster; struct dir *dsub; ushort nclu; int nentries; /* число записей в каталоге */ /* Коррекция cwd */ tail = cwd + strlen(cwd); *tail = '/'; strcpy(tail+1, name); if( create ){ /* создать */ sprintf( newname, "%s%s", root, cwd ); mkdir ( newname, 0755); } if( trace ) fprintf( mapfp, "\nDIR %s:", cwd); myCluster = Malloc( sizeof cluster ); dsub = (struct dir *) myCluster; nentries = nclu = 0; while( clu ){ if( trace ) traceclu(nclu++, clu); /* Прочесть очередной кластер каталога */ getCluster(clu, NULL,(long) CLU, myCluster); /* Обработать имена в этом кластере */ doDirectory(nentries, ENTRperCLUSTER, dsub); nentries += ENTRperCLUSTER; /* Взять следующий кластер */ clu = nextCluster(clu); } *tail = '\0'; free(myCluster); } /* Подсчет свободных и плохих кластеров. */ void countFree(){ int isFree = 0; /* свободные кластеры */ int isBad = 0; /* сбойные кластеры */ int isReserved = 0; /* спрятанные кластеры */ register ushort n = 0; register ushort clu; /* текущий анализируемый кластер */ int nline = 300; if( trace ) fprintf(mapfp, "\t\tFAT chart\n"); for(clu=0; clu < MAXCLU; clu++){ if( clu >= 2 ){ n = numCluster(clu); if( n == 0 ) isFree++; if( n == (bit16 ? 0xFFF7 : 0xFF7)) isBad++; if( n >= (bit16 ? 0xFFF0 : 0xFF0 ) && n < (bit16 ? 0xFFF7 : 0xFF7 )) isReserved++; } if( trace ){ if( nline >= 8){ nline = 0; fprintf( mapfp, "\n%03X:\t", clu ); } else nline++; fprintf( mapfp, "%03X ", n ); } } line('='); printf( "Свободно %ld, испорчено %ld, резерв %d кластеров\n", (long)isFree * CLU, /* в байтах */ (long)isBad * CLU, isReserved ); } void traceclu(nclu, clu) ushort nclu, clu; { if( nclu % 16 == 0 ) fprintf( mapfp, "\n\t" ); fprintf( mapfp, "%03X ", clu ); } #ifdef LOCAL_MALLOC /* Обратите внимание, что в этой программе память отводится malloc() и освобождается free() по принципу стека (LIFO). Мы могли бы переопределить стандартные функции malloc() и free(), заставив их работать со статической памятью! (Если мы напишем свою функцию с именем, как у стандартной, то будет использоваться НАША функция). */ static char allocArena[32 * 1024]; static char *top = allocArena; char *malloc(n){ char *ptr; /* округлить до целого числа слов */ /* деление с остатком */ /* число int-ов: */ n = (n + (sizeof(int)-1)) / sizeof(int); /* число char-ов:*/ n *= sizeof(int); ptr = top; top += n; return ptr; } free(ptr) char *ptr; { top = ptr; } #endif /*LOCAL_MALLOC*/ /* Пример 31 */ /* Интроспективная программа: печатает сама себя */ #include <stdio.h> char *text[] = { "#include <stdio.h>", "char *text[] = {", " NULL};", "/* Программа, печатающая свой собственный текст */", "main(){ int i;", " puts(text[0]); puts(text[1]);", " for(i=0; text[i]; i++) putq(text[i]);", " for(i=2; text[i]; i++) puts(text[i]);", "}", "putq(s) char *s; {", " printf(\"\\t\\\"\");", " while(*s){", " if(*s == '\"') printf(\"\\\\\\\"\");", " else if(*s == '\\\\') printf(\"\\\\\\\\\");", " else putchar(*s);", " s++;", " }", " printf(\"\\\",\\n\");", "}", NULL}; /* Программа, печатающая свой собственный текст */ main(){ int i; puts(text[0]); puts(text[1]); for(i=0; text[i]; i++) putq(text[i]); for(i=2; text[i]; i++) puts(text[i]); } putq(s) char *s; { printf("\t\""); while(*s){ if(*s == '"') printf("\\\""); else if(*s == '\\') printf("\\\\"); else putchar(*s); s++; } printf("\",\n"); } /* Пример 32 */ /* C beautify: программа cb.c, форматирующая исходный * текст программы на Си. Текст взят из дистрибутива UNIX */ #include <stdio.h> #include <stdlib.h> #define gets getlex #define puts putlex /* прототипы */ void main(int argc, char *argv[]); void ptabs( void ); int getch( void ); void puts( void ); int lookup( char *tab[] ); int gets( void ); void gotelse( void ); int getnl( void ); void comment( void ); int slevel[10]; int clevel = 0; int spflg[20][10]; int sind [20][10]; int siflev[10]; int sifflg[10]; int iflev = 0; int ifflg = -1; int level = 0; int ind[10] = { 0,0,0,0,0,0,0,0,0,0 }; int eflg = 0; int paren = 0; int pflg[10] = { 0,0,0,0,0,0,0,0,0,0 }; char lchar; char pchar; int aflg = 0; int ct; int stabs[20][10]; int qflg = 0; char *wif[] = { "if",NULL}; char *welse[] = { "else", NULL}; char *wfor[] = { "for" , NULL}; char *wds[] = { "case","default", NULL}; int j = 0; char string[200]; char cc; int sflg = 1; int peek = -1; int tabs = 0; int lastchar; int c; void main(int argc, char *argv[]) { if( argc > 1 ){ if( freopen( argv[1], "r", stdin ) == NULL ){ fprintf(stderr, "Can't open %s\n", argv[1] ); exit(1); } } if( argc > 2 ){ if( freopen( argv[2], "w", stdout ) == NULL ){ fprintf(stderr, "Can't create %s\n", argv[2] ); exit(1); } } while((c = getch()) != EOF){ switch(c){ case ' ': case '\t': if(lookup(welse) == 1){ gotelse(); if(sflg == 0 || j > 0) string[j++] = c; puts(); sflg = 0; if(getnl() == 1){ puts(); printf("\n"); sflg = 1; pflg[level]++; tabs++; } continue; } if(sflg == 0 || j > 0) string[j++] = c; continue; case '\n': if((eflg = lookup(welse)) == 1) gotelse(); puts(); printf("\n"); sflg = 1; if(eflg == 1){ pflg[level]++; tabs++; } else if(pchar == lchar) aflg = 1; continue; case '{': if(lookup(welse) == 1) gotelse(); siflev[clevel] = iflev; sifflg[clevel] = ifflg; iflev = ifflg = 0; clevel++; if(sflg == 1 && pflg[level] != 0){ pflg[level]--; tabs--; } string[j++] = c; puts(); getnl(); puts(); printf("\n"); tabs++; sflg = 1; if(pflg[level] > 0){ ind[level] = 1; level++; slevel[level] = clevel; } continue; case '}': clevel--; if((iflev = siflev[clevel]-1) < 0) iflev = 0; ifflg = sifflg[clevel]; if(pflg[level] >0 && ind[level] == 0){ tabs -= pflg[level]; pflg[level] = 0; } puts(); tabs--; ptabs(); if((peek = getch()) == ';'){ printf("%c;", c); peek = -1; } else printf("%c", c); getnl(); puts(); printf("\n"); sflg = 1; if(clevel < slevel[level])if(level > 0) level--; if(ind[level] != 0){ tabs -= pflg[level]; pflg[level] = 0; ind[level] = 0; } continue; case '"': case '\'': string[j++] = c; while((cc = getch()) != c){ string[j++] = cc; if(cc == '\\'){ string[j++] = getch(); } if(cc == '\n'){ puts(); sflg = 1; } } string[j++] = cc; if(getnl() == 1){ lchar = cc; peek = '\n'; } continue; case ';': string[j++] = c; puts(); if(pflg[level] > 0 && ind[level] == 0){ tabs -= pflg[level]; pflg[level] = 0; } getnl(); puts(); printf("\n"); sflg = 1; if(iflev > 0) if(ifflg == 1){ iflev--; ifflg = 0; } else iflev = 0; continue; case '\\': string[j++] = c; string[j++] = getch(); continue; case '?': qflg = 1; string[j++] = c; continue; case ':': string[j++] = c; if(qflg == 1){ qflg = 0; continue; } if(lookup(wds) == 0){ sflg = 0; puts(); } else{ tabs--; puts(); tabs++; } if((peek = getch()) == ';'){ printf(";"); peek = -1; } getnl(); puts(); printf("\n"); sflg = 1; continue; case '/': string[j++] = c; if((peek = getch()) != '*') continue; string[j++] = peek; peek = -1; comment(); continue; case ')': paren--; string[j++] = c; puts(); if(getnl() == 1){ peek = '\n'; if(paren != 0) aflg = 1; else if(tabs > 0){ pflg[level]++; tabs++; ind[level] = 0; } } continue; case '#': string[j++] = c; while((cc = getch()) != '\n') string[j++] = cc; string[j++] = cc; sflg = 0; puts(); sflg = 1; continue; case '(': string[j++] = c; paren++; if(lookup(wfor) == 1){ while((c = gets()) != ';'); ct=0; cont: while((c = gets()) != ')'){ if(c == '(') ct++; } if(ct != 0){ ct--; goto cont; } paren--; puts(); if(getnl() == 1){ peek = '\n'; pflg[level]++; tabs++; ind[level] = 0; } continue; } if(lookup(wif) == 1){ puts(); stabs[clevel][iflev] = tabs; spflg[clevel][iflev] = pflg[level]; sind[clevel][iflev] = ind[level]; iflev++; ifflg = 1; } continue; default: string[j++] = c; if(c != ',') lchar = c; } } } void ptabs( void ){ int i; for(i=0; i < tabs; i++) printf("\t"); } int getch( void ){ if(peek < 0 && lastchar != ' ' && lastchar != '\t') pchar = lastchar; lastchar = (peek<0) ? getc(stdin) : peek; peek = -1; return(lastchar); } void puts( void ){ if(j > 0){ if(sflg != 0){ ptabs(); sflg = 0; if(aflg == 1){ aflg = 0; if(tabs > 0) printf(" "); } } string[j] = '\0'; printf("%s",string); j = 0; } else{ if(sflg != 0){ sflg = 0; aflg = 0; } } } int lookup( char *tab[] ) { char r; int l,kk,k,i; if(j < 1) return(0); kk=0; while(string[kk] == ' ') kk++; for(i=0; tab[i] != 0; i++){ l=0; for(k=kk;(r = tab[i][l++]) == string[k] && r != '\0';k++); if(r == '\0' && (string[k] < 'a' || string[k] > 'z' || k >= j)) return(1); } return(0); } int gets( void ){ char ch; beg: if((ch = string[j++] = getch()) == '\\'){ string[j++] = getch(); goto beg; } if(ch == '\'' || ch == '"'){ while((cc = string[j++] = getch()) != ch) if(cc == '\\') string[j++] = getch(); goto beg; } if(ch == '\n'){ puts(); aflg = 1; goto beg; } else return(ch); } void gotelse( void ){ tabs = stabs[clevel][iflev]; pflg[level] = spflg[clevel][iflev]; ind[level] = sind [clevel][iflev]; ifflg = 1; } int getnl( void ){ while((peek = getch()) == '\t' || peek == ' '){ string[j++] = peek; peek = -1; } if((peek = getch()) == '/'){ peek = -1; if((peek = getch()) == '*'){ string[j++] = '/'; string[j++] = '*'; peek = -1; comment(); } else string[j++] = '/'; } if((peek = getch()) == '\n'){ peek = -1; return(1); } return(0); } void comment( void ){ rep: while((c = string[j++] = getch()) != '*') if(c == '\n'){ puts(); sflg = 1; } gotstar: if((c = string[j++] = getch()) != '/'){ if(c == '*') goto gotstar; goto rep; } }
© Copyright А. Богатырев, 1992-95 www.abyss-group.narod.ru
Си в UNIX
Назад | Содержание | Вперед