/*************************************************************************** * Copyright (C) 2009 by NPP SEMIKO (Russia, Novosibirsk) * * mail@semico.ru * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ /* Перекодирование текстового файла в набор файлов формата MKT (русская кодировка 866) для ЭКВМ серии Электроника МК. Одновременное перекодирование текста в формат блокнота MKN. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include // Коды выхода BSD from @(#)sysexits.h 8.1 (Berkeley) 6/2/93 // Copyright (c) 1987, 1993 // The Regents of the University of California. All rights reserved. #define EX_USAGE 64 /* command line usage error */ #define EX_DATAERR 65 /* data format error */ #define EX_NOINPUT 66 /* cannot open input */ #define EX_NOUSER 67 /* addressee unknown */ #define EX_NOHOST 68 /* host name unknown */ #define EX_UNAVAILABLE 69 /* service unavailable */ #define EX_SOFTWARE 70 /* internal software error */ #define EX_OSERR 71 /* system error (e.g., can't fork) */ #define EX_OSFILE 72 /* critical OS file missing */ #define EX_CANTCREAT 73 /* can't create (user) output file */ #define EX_IOERR 74 /* input/output error */ #define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */ #define EX_PROTOCOL 76 /* remote error in protocol */ #define EX_NOPERM 77 /* permission denied */ #define EX_CONFIG 78 /* configuration error */ // end sysexits.h char mkversion[]="Version 0.12"; /* 0.1 - первая версия 0.11 - вывод в файл MKN в формате программы primer.mkp; для сокращения файлов удаляются цепочки пробелов, последовательные переносы строк заменяются пустой строкой. 0.12 - изменение формата файла конфигурации mk.cfg */ int dos=0; // 0-GNU/Linux 1-DOS 2-Windows (Win32) char mes[24][256]; // сообщения программы char fname[6][256]; //0-TXT без расширения 1-TXT исходный 2-MKT 3-MKN int fname_vsego; // всего файлов в строке аргументов FILE *fp0, *fp1,*fp2, *fp3, *fp4; //потоки 0-CFG 1-TXT 2-MKT 3-MKN int mkiocharset; // 0=CP866|1=CP1251|2=KOI8R|3=UTF8|4=UCS2 кодировка ввода-вывода int txtiocharset; // 0=CP866|1=CP1251|2=KOI8R|3=UTF8|4=UCS2 кодировка входного файла int chislo_mkt; // количество mkt файлов на которые разбит текст char temp[256]; char ctemp[512]; /* вспомогательная строка */ char ctemp1[512]; /* вспомогательная строка */ char ctemptoa[40]; // вспомогательная строка для sprintf (DOS - itoa ltoa) unsigned char mktbuf[3104]; // буфер для записи MKT файла int mktpos; // текущая позиция в файле MKT - файл 3072 байта, строка 24 байта int mknpos; // MKN - первые черыре байта - начальная и конечная группа, размер от 4 до 524292 байт // каждая запись MKN - четыре числа по 8 байт во внутреннем формате ЭКВМ // 1 файл MKT соответствует 192 записи MKN int mktnom; // номер текущего mkt файла int mknnom; // номер текущего mkn файла long mkcharset[68][5]= //а=0 я=32 А=33 Я=65 0-866 1-1251 2-koi8 3-utf8 4-ucs2 {0xA0,0xE0,0xC1,0xD0B0,0x0430, // а 0xA1,0xE1,0xC2,0xD0B1,0x0431, // б 0xA2,0xE2,0xD7,0xD0B2,0x0432, 0xA3,0xE3,0xC7,0xD0B3,0x0433, 0xA4,0xE4,0xC4,0xD0B4,0x0434, 0xA5,0xE5,0xC5,0xD0B5,0x0435, // е 0xF1,0xB8,0xA3,0xD191,0x0451, // ё 0xA6,0xE6,0xD6,0xD0B6,0x0436, // ж 0xA7,0xE7,0xDA,0xD0B7,0x0437, 0xA8,0xE8,0xC9,0xD0B8,0x0438, 0xA9,0xE9,0xCA,0xD0B9,0x0439, 0xAA,0xEA,0xCB,0xD0BA,0x043A, 0xAB,0xEB,0xCC,0xD0BB,0x043B, 0xAC,0xEC,0xCD,0xD0BC,0x043C, 0xAD,0xED,0xCE,0xD0BD,0x043D, 0xAE,0xEE,0xCF,0xD0BE,0x043E, 0xAF,0xEF,0xD0,0xD0BF,0x043F, // п 0xE0,0xF0,0xD2,0xD180,0x0440, // р 0xE1,0xF1,0xD3,0xD181,0x0441, 0xE2,0xF2,0xD4,0xD182,0x0442, 0xE3,0xF3,0xD5,0xD183,0x0443, 0xE4,0xF4,0xC6,0xD184,0x0444, 0xE5,0xF5,0xC8,0xD185,0x0445, 0xE6,0xF6,0xC3,0xD186,0x0446, 0xE7,0xF7,0xDE,0xD187,0x0447, 0xE8,0xF8,0xDB,0xD188,0x0448, 0xE9,0xF9,0xDD,0xD189,0x0449, 0xEA,0xFA,0xDF,0xD18A,0x044A, 0xEB,0xFB,0xD9,0xD18B,0x044B, 0xEC,0xFC,0xD8,0xD18C,0x044C, 0xED,0xFD,0xDC,0xD18D,0x044D, 0xEE,0xFE,0xC0,0xD18E,0x044E, 0xEF,0xFF,0xD1,0xD18F,0x044F, // я 0x80,0xC0,0xE1,0xD090,0x0410, // А 0x81,0xC1,0xE2,0xD091,0x0411, 0x82,0xC2,0xF7,0xD092,0x0412, 0x83,0xC3,0xE7,0xD093,0x0413, 0x84,0xC4,0xE4,0xD094,0x0414, 0x85,0xC5,0xE5,0xD095,0x0415, 0xF0,0xA8,0xB3,0xD081,0x0401, // Ё 0x86,0xC6,0xF6,0xD096,0x0416, 0x87,0xC7,0xFA,0xD097,0x0417, 0x88,0xC8,0xE9,0xD098,0x0418, 0x89,0xC9,0xEA,0xD099,0x0419, 0x8A,0xCA,0xEB,0xD09A,0x041A, 0x8B,0xCB,0xEC,0xD09B,0x041B, 0x8C,0xCC,0xED,0xD09C,0x041C, 0x8D,0xCD,0xEE,0xD09D,0x041D, 0x8E,0xCE,0xEF,0xD09E,0x041E, 0x8F,0xCF,0xF0,0xD09F,0x041F, // П 0x90,0xD0,0xF2,0xD0A0,0x0420, // Р 0x91,0xD1,0xF3,0xD0A1,0x0421, 0x92,0xD2,0xF4,0xD0A2,0x0422, 0x93,0xD3,0xF5,0xD0A3,0x0423, 0x94,0xD4,0xE6,0xD0A4,0x0424, //Ф 0x95,0xD5,0xE8,0xD0A5,0x0425, 0x96,0xD6,0xE3,0xD0A6,0x0426, 0x97,0xD7,0xFE,0xD0A7,0x0427, 0x98,0xD8,0xFB,0xD0A8,0x0428, 0x99,0xD9,0xFD,0xD0A9,0x0429, 0x9A,0xDA,0xFF,0xD0AA,0x042A, 0x9B,0xDB,0xF9,0xD0AB,0x042B, 0x9C,0xDC,0xF8,0xD0AC,0x042C, 0x9D,0xDD,0xFC,0xD0AD,0x042D, 0x9E,0xDE,0xE0,0xD0AE,0x042E, 0x9F,0xDF,0xF1,0xD0AF,0x042F, // Я 0,0,0,0,0}; /*--------------------------------------------------------------------------*/ int dopmkn(void); int txt2file(void); int init_msg(void); void mkstrcpy (char*, char*, int , int ); int setmktname(void); int setmknname(void); /*--------------------------------------------------------------------------*/ int dopmkn(void) { int re=0; int k,k1,k2; int porjadok; for (k=0; k<768; k++) { ctemp[0]=0; temp[0]=0; for (k1=0; k1<4; k1++) { // сформировать буфер в ctemp и temp - 8 байт число для MKN - и записать его k2=mktbuf[4*k+k1]; sprintf(ctemptoa,"%i",k2); if (k2<100) strcat(ctemp,"0"); if (k2<10) strcat(ctemp,"0"); strcat(ctemp,ctemptoa); } // в ctemp - строка 12 цифр - дополнить её нулями strcat(ctemp,"00000000000000"); porjadok=11; // этот порядок соответствует двенадцатизначному числу while (ctemp[0]=='0') { porjadok--; if (porjadok<=0) {porjadok=0; goto a1;} // в ctemp одни нули for (k1=0; k1<32; k1++) { // сдвинуть влево вместе с "00..00"\0 ctemp[k1]=ctemp[k1+1]; } } a1: // перенести из ctemp в temp temp[0]=0; // знак положительный for (k1=0; k1<6; k1++) { temp[k1+1]=(ctemp[2*k1]-48)*16+ctemp[2*k1+1]-48; } // перенести порядок temp[7]=porjadok; // записать 8 байт из temp в MKN for (k1=0; k1<8; k1++) { if (fputc(temp[k1],fp3)==EOF) {re=EX_IOERR; goto end;} } } // увеличить счётчик MKN -файла на 192 группы (768/4=192) и записать mknpos+=192; fseek(fp3,2,SEEK_SET); // в поле последней записи if (fputc(mknpos%256,fp3)==EOF) {re=EX_IOERR; goto end;} if (fputc(mknpos/256,fp3)==EOF) {re=EX_IOERR; goto end;} fseek(fp3,0,SEEK_END); // обратно в конец файла end: return(re); } /*--------------------------------------------------------------------------*/ int txt2file(void) { int i,j,k,k1,k2,m; int re=0; int flag_probel=0; int flag_perenos=0; a0: if (fgets(ctemp,500,fp1)==NULL) goto zap; // очередная строка для разбора в ctemp ctemp[500]=0; // ограничить длину строки if (ctemp[0]==0) goto zap; // конец разбора - запись остатка в файл // перекодировать строку в 866 mkstrcpy(ctemp1,ctemp,0,txtiocharset); j=strlen(ctemp1); // строка для переноса в ctemp1 for (i=0; i=1)) { for (k1=mktpos; k1<24*((mktpos+48)%24); k1++) { // записать пустую строку в MKT mktbuf[mktpos]=32; mktpos++; } } if ((k==32)&&(flag_probel==0)) flag_probel=1; // цепочка пробелов заменяется одним if ((k==10)&&(flag_perenos==0)) flag_perenos=1; if (k==0) goto zap; if (mktpos>=3072) { // кончился очередной файл mkt // переписать буфер в файл for (k=0; k<3072; k++) { m=fputc(mktbuf[k],fp2); if (m==EOF) {re=EX_IOERR; goto end;} } fclose(fp2); // закрыть старый mktnom++; k=setmktname(); if (k!=0) {re=k; goto end;} // ошибка при генерации имени файла fp2=fopen(fname[2],"wb"); // открыть следующий MKT как двоичный для записи if (fp2==NULL) {re=EX_CANTCREAT; goto end;} printf("%s %s",fname[2],mes[0]); mktpos=0; // дополнить MKN файл k1=dopmkn(); if (k1!=0) {re=k1; goto end;} if (mknpos>=16384) { // этот файл кончился - закрыть его и открыть следующий fclose(fp3); k=setmknname(); if (k!=0) {re=k; goto end;} // ошибка при генерации имени файла fp3=fopen(fname[3],"wb"); // открыть следующий MKN как двоичный для записи if (fp3==NULL) {re=EX_CANTCREAT; goto end;} printf("%s %s",fname[3],mes[0]); mknpos=0; } } } goto a0; zap: for (i=mktpos; i<3072; i++) mktbuf[i]=0; mktpos=3072; for (k=0; k<3072; k++) { m=fputc(mktbuf[k],fp2); if (m==EOF) {re=EX_IOERR; goto end;} } // дополнить MKN файл k1=dopmkn(); if (k1!=0) {re=k1; goto end;} // закрывать MKT и MKN не нужно - закроется при выходе end: return(re); } /*--------------------------------------------------------------------------*/ int init_msg(void) { // инициализация списка сообщений 0-по умолчанию int re=0; if ((dos==1)||(dos==2)) strcpy(mes[0],"\r\n"); // DOS & Win - ВК + ПС else strcpy(mes[0],"\n"); // Linux - только ПС mkstrcpy(mes[1],"",mkiocharset,0); mkstrcpy(mes[2],"",mkiocharset,0); mkstrcpy(mes[3],"",mkiocharset,0); mkstrcpy(mes[4],"txt2mkt -h for help",mkiocharset,0); mkstrcpy(mes[5],"Текстовый файл не найден",mkiocharset,0); mkstrcpy(mes[6],"Файл не открыт ",mkiocharset,0); mkstrcpy(mes[7],"Файл MKT ",mkiocharset,0); end: return(re); } /*------------------------------------------------------ Перекодировка --------------*/ void mkstrcpy (char* str2, char* str1, int chset2, int chset1) { // перенос из str1 в str2 в кодировках chset1 chset2 соответственно //chset= 0=CP866|1=CP1251|2=KOI8R|3=UTF-8|4=UCS-2 int i,j,k,m; long l,l1,l2; if (chset1==chset2) {strcpy(str2,str1); goto end;} k=strlen(str1); if ((k==0) ||(chset1<0)||(chset1>4)||(chset2<0)||(chset2>4)) {str2[0]=0; goto end; } i=0; j=0; if (chset1==4) i=2; if (chset2==4) {str2[0]=0xFF; str2[1]=0xFE; j=2; } ci: if ((chset1==0)||(chset1==1)||(chset1==2)) {l=str1[i]; i++; if (l<0) l+=256; goto ci1; } if (chset1==3) {l1=str1[i]; l2=str1[i+1]; if (l1<0) l1+=256; if (l1<128) {i+=1; l=l1;} else {if (l2<0) l2+=256; i+=2; l=l1*256+l2; } goto ci1; } if (chset1==4) {l1=str1[i]; l2=str1[i+1]; if (l1<0) l1+=256; if (l2<0) l2+=256; i+=2; l=l1+l2*256; goto ci1; } ci1: l2=l; // поиск по массиву. если ничего не будет найдено - не перекодировать for (m=0; m<66; m++) { l1=mkcharset[m][chset1]; if (l1==l) l2=mkcharset[m][chset2]; } if ((chset2==0)||(chset2==1)||(chset2==2)) { // вставить один байт в строку str2[j]=(char)(l2%256); j++; goto cinext; } if (chset2==3) { if (l2<128) { // вставить один байт в строку str2[j]=(char)(l2%256); j++; goto cinext; } str2[j]=(char)((l2/256)%256); str2[j+1]=(char)(l2%256); j+=2; goto cinext; } if (chset2==4) { str2[j]=(char)(l2%256); str2[j+1]=(char)((l2/256)%256); j+=2; } cinext: if ((i>=k)||(j>254)) { str2[j]=0; str2[j+1]=0; goto end; } else goto ci; end: return; } //------------------------------------------ генерация имени файлов MKT MKNchislo_mkt int setmktname(void) { int re=0; // новое имя в fname[2] strcpy(fname[2],fname[0]); if (dos==1) { // для ДОС - урезать имя до нужного размера if (mktnom<10) {fname[2][7]=0; goto m1;} if ((mktnom>=10)&&(mktnom<100)) {fname[2][6]=0; goto m1;} if ((mktnom>=100)&&(mktnom<1000)) {fname[2][5]=0; goto m1;} if ((mktnom>=1000)&&(mktnom<10000)) {fname[2][4]=0; goto m1;} if ((mktnom>=10000)&&(mktnom<100000)) {fname[2][3]=0; goto m1;} re=EX_CANTCREAT; goto end; } m1: if (dos==1) sprintf(temp,"%s%i",fname[2],mktnom); else sprintf(temp,"%s.%i",fname[2],mktnom); strcpy(fname[2],temp); strcat(fname[2],".mkt"); end: return(re); } int setmknname(void) { int re=0; // новое имя в fname[2] strcpy(fname[3],fname[0]); if (dos==1) { // для ДОС - урезать имя до нужного размера if (mknnom<10) {fname[3][7]=0; goto m1;} if ((mknnom>=10)&&(mknnom<100)) {fname[3][6]=0; goto m1;} if ((mknnom>=100)&&(mknnom<1000)) {fname[3][5]=0; goto m1;} if ((mknnom>=1000)&&(mknnom<10000)) {fname[3][4]=0; goto m1;} if ((mknnom>=10000)&&(mknnom<100000)) {fname[3][3]=0; goto m1;} re=EX_CANTCREAT; goto end; } m1: if (dos==1) sprintf(temp,"%s%i",fname[3],mknnom); else sprintf(temp,"%s.%i",fname[3],mknnom); strcpy(fname[3],temp); strcat(fname[3],".mkn"); end: return(re); } //================================================================= MAIN int main(int argc, char *argv[]) { int i,j,k; char c; int flag_charset; int re=EXIT_SUCCESS; fp0=fp1=fp2=fp3=fp4=NULL; fname_vsego=0; mkiocharset=0; txtiocharset=0; chislo_mkt=0; // считывание файла конфигурации - если он есть fp0=fopen("mk.cfg","rb"); // открыть файл CFG для чтения if (fp0!=NULL) { // бинарный файл конфигурации - для переносимости - упрощает разбор в случае USC-2 // подготовка файла - отдельной программой конфигурирования пакета i=fgetc(fp0); if (i!=EOF) mkiocharset=i; // байт 0 - кодировка, c v0.12 изменён формат if ((mkiocharset<0)||(mkiocharset>4)) mkiocharset=0; fclose(fp0); } init_msg(); j=0; // разбор строки аргументов if (argc<=1) goto nach; for (i=1; i='a')&&(temp[j]<='z')) temp[j]-=32; // to A-Z } if ((strcmp(temp,"CP866")==0)||(strcmp(temp,"866")==0)||(strcmp(temp,"IBM866")==0)||(strcmp(temp,"CP-866")==0)||(strcmp(temp,"IBM-866")==0)) {flag_charset=2; txtiocharset=0;} if ((strcmp(temp,"CP1251")==0)||(strcmp(temp,"1251")==0)||(strcmp(temp,"CP-1251")==0)) {flag_charset=2; txtiocharset=1;} if ((strcmp(temp,"KOI8R")==0)||(strcmp(temp,"KOI8")==0)||(strcmp(temp,"KOI8-R")==0)||(strcmp(temp,"KOI-8")==0)) {flag_charset=2; txtiocharset=2;} if ((strcmp(temp,"UTF-8")==0)||(strcmp(temp,"UTF8")==0)) {flag_charset=2; txtiocharset=3;} if ((strcmp(temp,"UCS-2")==0)||(strcmp(temp,"UCS2")==0)) {flag_charset=2; txtiocharset=4;} } else { // file j=fname_vsego; if (j<0) j=0; if (j>4) j=4; strncpy(fname[j+1],argv[i],255); if (j<4) fname_vsego++; } } else { flag_charset=0; c=argv[i][1]; if ((c=='h')||(c=='H')||(c=='?')) { /* help */ printf("txt2mkt - EKVM Elektronika MK, convertor TXT to MKT and MKN files %s",mes[0]); printf("txt2mkt TXTfile [key] %s",mes[0]); printf("\t-h,-H,-?\tthis help; %s",mes[0]); printf("\t-v,-V\tversion; %s",mes[0]); printf("\t-c,-C\trussian charset for TXTfile (-c CP866|CP1251|KOI8R|UTF8|UCS2); %s",mes[0]); printf("\t-w,-W\twarranty and copyright %s",mes[0]); printf("Russian charset is "); switch(mkiocharset) {case 0: printf("CP866"); break; case 1: printf("CP1251"); break; case 2: printf("KOI8R"); break; case 3: printf("UTF8"); break; case 4: printf("UCS2"); break; default: printf("?"); } goto end; } if ((c=='v')||(c=='V')) { /* version */ printf(mkversion); if (dos==0) printf(" (GNU/Linux)"); if (dos==1) printf(" (DOS)"); if (dos==2) printf(" (Win32)"); goto end; } if ((c=='c')||(c=='C')) { flag_charset=1; goto nextargv; } if ((c=='w')||(c=='W')) { /* copyleft & warranty */ printf("Copyright (C) 2009 by NPP SEMIKO (Russia, Novosibirsk) %s%s",mes[0],mes[0]); printf("This program is free software; you can redistribute it and/or modify %s",mes[0]); printf("it under the terms of the GNU General Public License as published by %s",mes[0]); printf("the Free Software Foundation; either version 2 of the License, or %s",mes[0]); printf("(at your option) any later version. %s%s",mes[0],mes[0]); printf("This program is distributed in the hope that it will be useful, %s",mes[0]); printf("but WITHOUT ANY WARRANTY; without even the implied warranty of %s",mes[0]); printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %s",mes[0]); printf("GNU General Public License for more details. %s%s",mes[0],mes[0]); printf("You should have received a copy of the GNU General Public License %s",mes[0]); printf("along with this program; if not, write to the Free Software %s",mes[0]); printf("Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"); goto end; } //if (flag_charset!=2) printf(mes[4]); goto end; // del v0.12 } nextargv:; } nach: if (fname_vsego<=0) {printf(mes[4]); re=EX_USAGE; goto end;} // нет файла TXT fp1=fopen(fname[1],"rt"); // открыть TXT как текст для чтения if (fp1==NULL) {printf(mes[5]); re=EX_NOINPUT; goto end;} // файл TXT не открыт // найти имя файла без расширения i=0; k=strlen(fname[1]); if (dos==0) goto m1; // в Linux - расширение не трогать for (i=k; i>0; i--) { if (fname[1][i]=='.') {i=k; goto m1;} // в других ОС убрать текущее расширение у имени файла } m1: strncpy(fname[0],fname[1],248); if ((i>0)&&(i