home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 613b.lha / VIF / vif.c < prev    next >
C/C++ Source or Header  |  1991-10-11  |  11KB  |  481 lines

  1. /* Very Intelligent filter */
  2. /* © 1990 Pagani Massimiliano */
  3.  
  4. /* Per compilare col Lattice C:        */
  5. /*    lc -L -cfist -d0 vif.c        */
  6.  
  7. /* Questo filtro dovrebbe fare le seguenti cose:            */
  8. /* - Rimuovere i caratteri vuoti (spazi, tab) alla fine delle linee    */
  9. /* - Sostituire spazi consecutivi con caratteri tab rispettando le di-    */
  10. /*   mensioni                                */
  11. /* - Rimuovere gli spazi coperti da un tab.                */
  12. /* - Rimuovere i newline alla fine del file.                */
  13. /* - i ^Z, ^M                                */
  14. /* opzionalmente:                            */
  15. /* - rimuovere le sequenze di escape.                    */
  16.  
  17.  
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <error.h>
  21. #include <ctype.h>
  22. #include <dos.h>
  23. #include <fcntl.h>
  24.  
  25. /* Stato dell'automa */
  26. typedef enum {RESET, SPAZIO, TAB, NEWLINE} STATO;
  27.  
  28. #ifdef LATTICE
  29. /* Gli errori vengono trovati controllando la errno */
  30. /* prototipi */
  31.   void ShowHelp(void);
  32.   BOOL copyfile( unsigned char *, unsigned char * );
  33.   BOOL OutChars( int, unsigned char, FILE * );
  34.   void ExaustEscape( unsigned char, FILE *, FILE * );
  35.   STATO DoSpazio( STATO, int *, int *, int * );
  36.   void DoTab( STATO, int *, int *, int * );
  37.   void DoNewLines( STATO, int *, int *, int *, int * );
  38.   void DoFilter( FILE *, FILE *, BOOL, BOOL, BOOL );
  39.   int main( int, char ** );
  40. #else
  41. #  define FALSE    0L
  42. #  define TRUE    (!FALSE)
  43. typedef int BOOL;
  44. #endif
  45.  
  46. #undef DEBUG
  47.  
  48.  
  49. #define TABSIZE    8
  50. #define ISTAB(col)    (!(((col)-1)-TABSIZE*(((col)-1)/TABSIZE)))
  51.         /* è una macro che ritorna TRUE quando la colonna attuale è */
  52.         /* una tabulazione, FALSE altrimenti */
  53. #define NEXTTAB(col)    ((col)+TABSIZE-(((col)-1)%TABSIZE))
  54.         /* ritorna la prossima possizione di tabulazione */
  55.  
  56. /* Variabili importate */
  57. extern int errno;
  58.  
  59.  
  60. void
  61. ShowHelp()
  62. {
  63.   puts("converts spaces into tabs,");
  64.   puts("removes useless spaces, tabs, control chars and");
  65.   puts("    escape sequences");
  66.   puts("Usage:");
  67.   puts("  vif [s] [<file> | (<filein> <fileout>)]");
  68.   puts("[s] any combination of switches precedeed by '-':");
  69.   puts("  e    do not strip escape sequences.");
  70.   puts("  q    no statistic at the end.");
  71.   puts("  p    progressing display.");
  72.   puts("If no files specified stdin and stdout will be used.");
  73.   puts("If only one file, the filtering will be done on a");
  74.   puts("temporary file (in T:) then the result will be copied");
  75.   puts("onto the original file (WARNING).");
  76.   puts("If two files specified filtering will be applied on");
  77.   puts("<filein> and result in <fileout>.");
  78. }
  79.  
  80. BOOL
  81. copyfile( name_in, name_out )
  82. unsigned char * name_in;
  83. unsigned char * name_out;
  84. {
  85. int fd_in, fd_out;
  86. char buffer[ BUFSIZ ];
  87. int count = -1L;
  88.  
  89.   fd_in = open( name_in, O_RDONLY );
  90.   fd_out = open( name_out, O_CREAT | O_WRONLY | O_TRUNC, 0 );
  91.   if( fd_in && fd_out ){
  92.     while( (count = read( fd_in, buffer, BUFSIZ )) > 0){
  93.       if( write( fd_out, buffer, count ) != count ){
  94.     printf("problema in scrittura\n");
  95.     break;
  96.       }
  97.     }
  98.     close( fd_in );
  99.     close( fd_out );
  100.   }
  101. # ifdef DEBUG
  102.     printf("errno = %d\n", errno );
  103. # endif
  104.   return( (BOOL) errno );
  105. }
  106.  
  107. BOOL
  108. OutChars( n, c, out )
  109. int n;
  110. unsigned char c;
  111. FILE *out;
  112. {
  113.  
  114. #ifdef DEBUG
  115.   printf("scrivo %d ", n );
  116.   switch( c ){
  117.     case ' ':
  118.       printf("spazi\n");
  119.       break;
  120.     case '\n':
  121.       printf("nl\n");
  122.       break;
  123.     case '\t':
  124.       printf("tab\n");
  125.       break;
  126.   }
  127. #endif
  128.  
  129.   for( ; n > 0; n-- ){
  130.     putc( c, out );
  131.   }
  132.   return( (BOOL) !errno );    /* (errno == 0) -> ok */
  133. }
  134.  
  135. /* Esaurisce la sequenza di escape */
  136.  
  137. void
  138. ExaustEscape( c, in, out )
  139. unsigned char c;
  140. FILE *in;
  141. FILE *out;
  142. {
  143. enum { ESC1B, ESC9B, NUMERO, FINE } stato;
  144.  
  145.   if( c == 0x1B ) stato = ESC1B;
  146.   else stato = ESC9B;
  147.   while( stato != FINE ){
  148.     c = getc( in );
  149.     if( out ) putc( c, out );
  150.     switch( stato ){
  151.       case ESC1B:
  152.     switch( c ){
  153.       case '[':
  154.         stato = ESC9B;
  155.         break;
  156.       default:
  157.         stato = FINE;
  158.     }
  159.     break;
  160.       case ESC9B:
  161.     if( isdigit( c ) || (c==';') ){
  162.       stato = NUMERO;
  163.     }
  164.     else stato = FINE;
  165.     break;
  166.       case NUMERO:
  167.     if( !isdigit( c ) && (c != ';') ){
  168.       stato = FINE;
  169.     }
  170.     break;
  171.     }
  172.   }
  173. }
  174.  
  175. /* risolve il problema quando il carattere letto è uno spazio */
  176.  
  177. STATO
  178. DoSpazio( stato, col, numSpazi, numTab )
  179. STATO stato;
  180. int *col, *numSpazi, *numTab;
  181. {
  182.  
  183.   (*col)++;
  184.   switch( stato ){
  185.     case RESET:
  186.     case SPAZIO:
  187.       *numSpazi = (stato == RESET) ? 1 : *numSpazi+1;
  188.       if( ISTAB( *col ) ){
  189.     *numSpazi = 0;
  190.     (*numTab)++;
  191.     stato = TAB;
  192.       }
  193.       else stato = SPAZIO;
  194.       break;
  195.     case TAB:
  196.     /* ci sono dei tab, quindi uno spazio */
  197.       (*numSpazi)++;
  198.       stato = SPAZIO;
  199.       break;
  200.     case NEWLINE:
  201.       *numSpazi = 1;
  202.       stato = SPAZIO;
  203.       break;
  204.   }
  205.   return( stato );
  206. }
  207.  
  208. /* risolve il problema quando il carattere letto è un tab */
  209.  
  210. void
  211. DoTab( stato, col, numSpazi, numTab )
  212. STATO stato;
  213. int *col;
  214. int *numSpazi, *numTab;
  215. {
  216.  
  217.   *col = NEXTTAB( *col );
  218.   switch( stato ){
  219.     case NEWLINE:
  220.     case RESET:
  221.       *numTab = 1;
  222.       break;
  223.     case SPAZIO:
  224.     /* un certo numero di spazi, quindi un tab */
  225.     /* al massimo una tabulazione, quindi il tab copre gli spazi */
  226.       (*numTab)++;
  227.       *numSpazi = 0;
  228.       break;
  229.     case TAB:
  230.       (*numTab)++;
  231.       break;
  232.   }
  233. }
  234.  
  235. void
  236. DoNewLines( stato, col, numSpazi, numTab, numNewLine )
  237. STATO stato;
  238. int *col;
  239. int *numSpazi, *numTab, *numNewLine;
  240. {
  241.  
  242.   *col = 1;
  243.   switch( stato ){
  244.     case RESET:
  245.       *numNewLine = 1;
  246.       break;
  247.     case SPAZIO:
  248.     case TAB:
  249.       /* abbiamo dei vuoti seguiti da un newLine */
  250.       *numTab = *numSpazi = 0;
  251.     case NEWLINE:
  252.       (*numNewLine)++;
  253.       break;
  254.   }
  255. }
  256.  
  257. void
  258. DoFilter( in, out, noStat, stripESC, progress )
  259. FILE *in, *out;
  260. BOOL noStat, stripESC;    /* flags */
  261. BOOL progress;
  262. {
  263. STATO stato;        /* stato dell'automa */
  264. int c;            /* ultimo carattere letto */
  265. int char_in = 0L;    /* # di caratteri letto */
  266. int char_out = 0L;    /* # caratteri scritti */
  267. BOOL lineaVuota;    /* la linea che stiamo leggendo è vuota ? */
  268. int numSpazi, numTab, numNewLine;
  269.             /* # spazi, tab e nl consecutivi */
  270. int col;        /* colonna attuale */
  271. register int linea;    /* # di linea attuale */
  272. char count = 0;        /* contatore simbolini */
  273. register int tlinea=0;
  274.  
  275. #ifdef DEBUG
  276.   printf("DoFilter: inizio\n");
  277. #endif
  278.  
  279.   col = linea = 1L;
  280.   numSpazi = numTab = numNewLine = 0L;
  281.   lineaVuota = TRUE;
  282.   stato = RESET;
  283.   do {
  284.     c = getc( in );
  285.     char_in++;
  286.  
  287. #ifdef DEBUG
  288.     printf("%d %d -> letto %2x", col, linea, c );
  289.     if( c > 32 ) printf("\t%c", c );
  290.     putchar( '\n' );
  291. #endif
  292.     if( progress && ((linea>>4) != tlinea) ){
  293.       tlinea = linea>>4;
  294.       putchar( '#' );
  295.       if( ++count > 40 ){
  296.     count = 0;
  297.     putchar( '\n' );
  298.       }
  299.       fflush( stdout );
  300.     }
  301.     switch( c ){
  302.       case ' ':
  303.     stato = DoSpazio( stato, &col, &numSpazi, &numTab );
  304.     break;
  305.       case '\t':
  306.     DoTab( stato, &col, &numSpazi, &numTab );
  307.     stato = TAB;
  308.     break;
  309.       case '\n':
  310.     DoNewLines( stato, &col, &numSpazi, &numTab, &numNewLine );
  311.     stato = NEWLINE;
  312.     linea++;
  313.     lineaVuota = TRUE;
  314.     break;
  315.       case 0xD:
  316.       case 0x1A:
  317.     /* ignoriamo i CR e gli EOF dei baracchi */
  318.     break;
  319.       case 0xC:     /* Form Feed */
  320.     putc( c, out );
  321.     char_out++;
  322.     col = 1;
  323.     lineaVuota = TRUE;
  324.     break;
  325.       case 0x1B:    /* Escape sequence */
  326.       case 0x9B:
  327.     ExaustEscape( (unsigned char) c, in, (stripESC ? NULL : out) );
  328.     break;
  329.       case EOF:
  330.     break;
  331.       default:
  332.     lineaVuota = FALSE;
  333.     col++;
  334.     char_out++;
  335.     if( numNewLine > 0 ){
  336.       OutChars( numNewLine, '\n', out );
  337.       char_out += numNewLine;
  338.       numNewLine = 0L;
  339.     }
  340.     if( numTab > 0 ){
  341.       OutChars( numTab, '\t', out );
  342.       char_out += numTab;
  343.       numTab = 0L;
  344.     }
  345.     if( numSpazi > 0 ){
  346.       OutChars( numSpazi, ' ', out );
  347.       char_out += numSpazi;
  348.       numSpazi = 0L;
  349.     }
  350.     putc( c, out );
  351.     stato = RESET;
  352.     break;
  353.     }
  354.   } while( (c != EOF) && (errno==0) );
  355.   if( errno ){
  356.     perror("vif");
  357.   }
  358.   else {
  359.     if( progress ) putchar( '\n' );
  360.     if( !noStat ){
  361.       printf("processate %ld linee\n", linea );
  362.       printf("letti   %ld caratteri\n", --char_in );
  363.       printf("scritti %ld caratteri\n", char_out );
  364.       if( char_out > 0 ){
  365.     printf("Compressed %ld%%\n", 100*(char_in - char_out)/char_out );
  366.       }
  367.     }
  368.   }
  369. }
  370.  
  371. int
  372. main( argc, argv )
  373. int argc;
  374. char **argv;
  375. {
  376. int ind;
  377. char *copt;    /* puntatore opzione corrente */
  378. FILE *in;
  379. FILE *out;
  380. BOOL oneFile = FALSE;    /* lavora su un file temporaneo */
  381. BOOL noStat = FALSE;    /* nessuna statistica alla fine */
  382. BOOL stripESC = TRUE;    /* toglie gli escape */
  383. unsigned char tmpname[ FMSIZE ];    /* nome file temporaneo */
  384. int count;        /* # del file in area temporanea */
  385. BOOL done = FALSE;    /* Finito */
  386. BOOL progress = FALSE;    /* indica il progredire */
  387.  
  388.   printf("VIF: very intelligent filter\n");
  389.   printf(" © 1990 Pagani Massimiliano\n");
  390.   printf("  ShareWare - see doc file\n");
  391.   printf("----------------------------\n");
  392.   if( (argc == 2) && (*argv[1] == '?') ){
  393.     ShowHelp();
  394.     exit( 0L );
  395.   }
  396.   if( (argc > 1) && (*argv[1] == '-')){
  397.     /* sono state specificate delle opzioni */
  398.     for( copt=argv[1]+1; *copt; copt++ ){
  399.       switch( *copt ){
  400.     case 'e':    /* conserviamo le seq. di escape */
  401.       stripESC = FALSE;
  402.       break;
  403.     case 'q':    /* quiet */
  404.       noStat = TRUE;
  405.       break;
  406.     case 'p':    /* indica il progredire */
  407.       progress = TRUE;
  408.       break;
  409.     default:
  410.       printf("Ignoro -%c in quanto non valido. \n", *copt );
  411.       }
  412.     }
  413.     ind = 2;
  414.   }
  415.   else {
  416.     ind = 1;
  417.   }
  418.   if( ind == argc ){
  419.     progress = FALSE;    /* altrimenti rompiamo le scatole */
  420.     noStat = TRUE;    /* idem con patate */
  421.     in = stdin;
  422.     out = stdout;
  423. #   ifdef DEBUG
  424.       printf("Applico il filtro sullo stdin, output su stdout\n");
  425. #   endif
  426.   }
  427.   else if( (ind+1) == argc ){
  428. #   ifdef DEBUG
  429.       printf("Applico il filtro su %s out in temp\n", argv[ind]);
  430. #   endif
  431.     /* c'è un solo file */
  432.     oneFile = TRUE;
  433.     in = fopen( argv[ind], "r" );
  434.     for( count=0; !done; count++ ){
  435.       sprintf( tmpname, "T:viftemp%d", count );
  436.       if( access( tmpname, 0 ) == -1 ){
  437.     /* Un errore o semplicemente non c'è */
  438.     if( errno != ENOENT ){
  439.       out = NULL;
  440.       perror( tmpname );
  441.     }
  442.     else {
  443.       out = fopen( tmpname, "w" );
  444.       errno = 0L;
  445.     }
  446.     done = TRUE;
  447.       }
  448.     }
  449.   }
  450.   else {
  451.     in = fopen( argv[ind], "r" );
  452.     out = fopen( argv[ind+1], "w" );
  453. #ifdef DEBUG
  454.     printf("Applico il filtro sul file \"%s\" output su \"%s\"\n", argv[1], argv[ind+1] );
  455. #endif
  456.   }
  457.   if( !in ){
  458.     fprintf( stderr, "non riesco ad aprire il file %s in lettura\n", argv[ind] );
  459.     exit( 10L );
  460.   }
  461.   if( !out ){
  462.     fprintf( stderr, "non riesco ad aprire il file %s in scrittura\n", argv[ind+1] );
  463.     exit( 11L );
  464.   }
  465.   DoFilter( in, out, noStat, stripESC, progress );
  466.   if( oneFile && (errno==0) ){
  467.     fclose( in );
  468.     fclose( out );
  469.     if( !copyfile( tmpname, argv[ ind ]) ){
  470.       remove( tmpname );
  471.     }
  472.     else {
  473.       puts("problemi nel copiare il file temporaneo");
  474.       puts("recupera il contenuto del file in:");
  475.       puts( tmpname );
  476.     }
  477.   }
  478.  
  479.   return( errno );
  480. }
  481.