home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / qc / qc20 / crlf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-12-07  |  9.1 KB  |  297 lines

  1. /* CRLF.C - Translates files for use in the QuickC editor.
  2.  *
  3.  * Copyright (c) 1988-1989, Microsoft Corporation
  4.  *
  5.  * A program list is not required to create CRLF from inside QC. No
  6.  * special options are required.
  7.  *
  8.  * The QuickC editor has the following restrictions on the files it
  9.  * can edit:
  10.  *
  11.  *   - All lines must be terminated by a carriage return (CR) followed
  12.  *     by a line feed (LF)--ASCII codes 0x0D/0x0A.
  13.  *
  14.  *   - Character 0 is not allowed.  All other characters in the
  15.  *     range 1 to 255 are allowed.
  16.  *
  17.  * The editor specifically handles CR (0x0D), LF (0x0A), and HT (0x09).
  18.  * Since other control characters may be undesirable, CRLF allows the
  19.  * user to optionally change control characters to a specified character
  20.  * or to simply remove them. The syntax is
  21.  *
  22.  *      CRLF <infile> <outfile> [/c<ascii>]
  23.  *
  24.  * where <infile> is the file to be translated, <outfile> is the new
  25.  * translated file, and <ascii> is the ASCII code for the character
  26.  * to which control characters (except CR, LF, and HT) will be translated.
  27.  * The ASCII code may be entered in decimal (ddd), octal (0ddd), or
  28.  * hexadecimal (0xddd).
  29.  *
  30.  * For example, /c32 will translate all control characters to spaces.
  31.  * If <ascii> is given as 0, control characters will be removed rather
  32.  * than translated. If /c is not given, the program will prompt for
  33.  * translation characters.
  34.  */
  35.  
  36. #include <stdio.h>
  37. #include <io.h>
  38. #include <conio.h>
  39. #include <stdlib.h>
  40. #include <memory.h>
  41. #include <ctype.h>
  42.  
  43. /* Constants */
  44. #define NUM_CHARS   32  /* Total number of control characters */
  45.  
  46. #define HT      0x09    /* Horizontal tab character           */
  47. #define LF      0x0A    /* Linefeed character                 */
  48. #define CR      0x0D    /* Carriage-return character          */
  49.  
  50. #define SKIP    0       /* Filter out control characters      */
  51. #define PROMPT  -1      /* Get translation from prompts       */
  52.  
  53. /* Global variables. Note that the compiler initializes global arrays
  54.  * to 0. The code in translate_char() depends on the following global
  55.  * array being initialized to 0.
  56.  */
  57. int mapping[NUM_CHARS];
  58.  
  59. int global_trans = PROMPT;
  60.  
  61. /* Function prototypes */
  62. void translate_file( FILE *fdIn, FILE *fdOut );
  63. int  translate_char( int line, int c );
  64.  
  65. /* main - opens input and output files and translates them.
  66.  *
  67.  * Params: argc - count of arguments
  68.  *         argv - array of argument strings
  69.  *
  70.  * Return: None
  71.  */
  72. void main( int argc, char *argv[] )
  73. {
  74.     FILE *fdInput;
  75.     FILE *fdOutput;
  76.     int  c;
  77.  
  78.     /* Check command line arguments for validity and print syntax
  79.      * prompt if invalid.
  80.      */
  81.     if( (argc != 3) && (argc != 4) )
  82.     {
  83.         fprintf( stderr, "SYNTAX: crlf <infile> <outfile> [/c<ascii>]\n" );
  84.         exit( 1 );
  85.     }
  86.  
  87.     /* Check for the /c (or -c) option. If present, read in the
  88.      * global translation value.
  89.      */
  90.     if( argc == 4 )
  91.     {
  92.         if( ((argv[3][0] == '/') || (argv[3][0] == '-')) &&
  93.             (toupper( argv[3][1] ) == 'C') )
  94.         {
  95.             sscanf( &argv[3][2], "%i", &global_trans );
  96.             if( global_trans > 255 )
  97.             {
  98.                 fprintf( stderr, "crlf: unknown translation character\n" );
  99.                 global_trans = PROMPT;
  100.             }
  101.         }
  102.         else
  103.         {
  104.             fprintf( stderr, "crlf: fatal error: unknown option '%s'\n",
  105.                      argv[3] );
  106.             exit( 1 );
  107.         }
  108.     }
  109.  
  110.     /* Try to open the input and output files in binary mode. */
  111.     if( (fdInput = fopen( argv[1], "rb" )) == NULL )
  112.     {
  113.         fprintf( stderr, "crlf: fatal error: can't open '%s'\n", argv[1] );
  114.         exit( 1 );
  115.     }
  116.  
  117.     if( !access( argv[2], 0 ) )
  118.     {
  119.         printf( "File exists. Overwrite? " );
  120.         c = getch();
  121.         if( c != 'y' && c != 'Y' )
  122.             exit( 1 );
  123.         printf( "\n" );
  124.     }
  125.     if( (fdOutput = fopen( argv[2], "wb" )) == NULL )
  126.     {
  127.         fclose( fdInput );
  128.         fprintf( stderr, "crlf: fatal error: can't open '%s'\n", argv[2] );
  129.         exit( 1 );
  130.     }
  131.  
  132.     /* Translate the input file to the output file. */
  133.     translate_file( fdInput, fdOutput );
  134.  
  135.     /* Close the files and exit. */
  136.     fclose( fdInput );
  137.     fclose( fdOutput );
  138.     exit( 0 );
  139. }
  140.  
  141.  
  142. /* translate_file - translates file for use in QuickC editor. Checks
  143.  * each character to see if it is a control character, and if so,
  144.  * handles appropriately.
  145.  *
  146.  * Params: fdIn - input file handle, as obtained from fopen()
  147.  *         fdOut - output file handle, as obtained from fopen()
  148.  *
  149.  * Return: None
  150.  *
  151.  * Uses:   trans_mode - character to translate to
  152.  */
  153. void translate_file( FILE *fdIn, FILE *fdOut )
  154. {
  155.     int    c;
  156.     int    i;
  157.     int    line = 1;
  158.  
  159.     /* Loop until the end of the file, reading each character from
  160.      * the input file and writing it to the output file. Handle
  161.      * control characters; pass other characters through unchanged.
  162.      * Note * that a return value of EOF does NOT necessarily indicate
  163.      * the end of the file--feof() must be called to verify that
  164.      * the end of file has actually been reached.
  165.      */
  166.     while( ((c = getc( fdIn )) != EOF) || (!feof( fdIn )) )
  167.     {
  168.  
  169.         /* If CR, check and handle the next character. */
  170.         if( c == CR )
  171.         {
  172.             /* Get the next key. */
  173.             c = getc( fdIn );
  174.  
  175.             /* If we've reached the end of file, write character and
  176.              * break loop to terminate function.
  177.              */
  178.             if( (c == EOF) && (feof( fdIn )) )
  179.             {
  180.                 putc( CR, fdOut );
  181.                 break;
  182.             }
  183.  
  184.             /* If it's a LF, write the CR/LF, increment the line count,
  185.              * and use the continue statement to return to the top of
  186.              * the loop for the next character.
  187.              */
  188.             else if( c == LF )
  189.             {
  190.                 putc( CR, fdOut );
  191.                 putc( LF, fdOut );
  192.                 ++line;
  193.                 continue;
  194.             }
  195.  
  196.             /* If it's a CR with no following LF, skip or translate it. */
  197.             else
  198.             {
  199.                 if( global_trans != SKIP )
  200.                 {
  201.                     putc( translate_char( line, CR ), fdOut );
  202.                 }
  203.             }
  204.         }
  205.  
  206.         /* If it's LF with no preceeding CR (common in files uploaded
  207.          * from Unix or Macintosh), write a CR/LF and increment the
  208.          * line count.
  209.          */
  210.         else if( c == LF )
  211.         {
  212.             putc( CR, fdOut );
  213.             putc( LF, fdOut );
  214.             ++line;
  215.         }
  216.  
  217.         /* If it's a control character that we haven't already handled,
  218.          * skip or translate it (depending on value of global_trans).
  219.          */
  220.         else if( (c != HT) && (c < NUM_CHARS) )
  221.         {
  222.             if( global_trans != SKIP )
  223.                 putc( translate_char( line, c ), fdOut );
  224.         }
  225.  
  226.         /* Otherwise, just write the character to the output file. */
  227.         else
  228.             putc(c, fdOut);
  229.     }
  230. }
  231.  
  232.  
  233. /* translate_char - translates a control character. If a translate
  234.  * character was provided on the command line, it is used. Otherwise
  235.  * the user is prompted for a translation character. This character
  236.  * is put in the appropriate element of the mapping[] array for future
  237.  * reference.
  238.  *
  239.  * For example, if we find character 3, and the user wants to map
  240.  * this to character 42, we set mapping[3] = 42. Next time we encounter
  241.  * character 3, we look at mapping[3] and substitute character 42
  242.  * without asking.
  243.  *
  244.  * Params: line - line number in which the character was found
  245.  *         c - character to be translated
  246.  *
  247.  * Return: Translated value of character (may be same as original
  248.  *         character if user didn't want to translate it)
  249.  *
  250.  * Uses:   trans_mode - character to translate to
  251.  *         mapping - array of translatable characters
  252.  */
  253. int translate_char( int line, int c )
  254. {
  255.     int  new_val;
  256.  
  257.     /* If command-line translation code was given, return it. */
  258.     if( global_trans != PROMPT )
  259.         return( global_trans );
  260.  
  261.     /* Otherwise, check to see if we've already got a translated value
  262.      * for this character. If so, return that value.
  263.      */
  264.     if( mapping[c] != 0 )
  265.         return( mapping[c] );
  266.  
  267.     /* Prompt for a translation value. We can't accept 0 or numbers
  268.      * larger than 255, so loop until we get a valid translation
  269.      * character. The for loop without any parameters will loop until
  270.      * a break statement is encountered. The scanf %i specifier is given
  271.      * so that the user can enter the ASCII code in decimal (ddd),
  272.      * octal (0ddd), or hexadecimal (0xddd).
  273.      *
  274.      * A different input mechanism could be implemented here.
  275.      * For example, you could use getche() to allow the user to
  276.      * type in the replacement character directly rather than
  277.      * entering an ASCII code.
  278.      */
  279.     printf( "Control character %u in line %u:  ", c, line );
  280.     for( ;; )
  281.     {
  282.         printf( "Enter ASCII translation code: " );
  283.         scanf( "%i", &new_val );
  284.         if( (new_val == 0) || (new_val > 255) )
  285.         {
  286.             printf( "Invalid translation value\n" );
  287.             fflush( stdin );
  288.         }
  289.         else
  290.             break;
  291.     }
  292.  
  293.     /* Remember the translated value in mapping[c]. */
  294.     mapping[c] = new_val;
  295.     return( new_val );
  296. }
  297.