1/* 2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights 7 * Reserved. This file contains Original Code and/or Modifications of 8 * Original Code as defined in and that are subject to the Apple Public 9 * Source License Version 1.0 (the 'License'). You may not use this file 10 * except in compliance with the License. Please obtain a copy of the 11 * License at http://www.apple.com/publicsource and read it before using 12 * this file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 19 * License for the specific language governing rights and limitations 20 * under the License." 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24/* 25 * decomment.c 26 * 27 * Removes all comments and (optionally) whitespace from an input file. 28 * Writes result on stdout. 29 */ 30 31#include <stdio.h> 32#include <ctype.h> /* for isspace */ 33#include <libc.h> 34 35/* 36 * State of input scanner. 37 */ 38typedef enum { 39 IS_NORMAL, 40 IS_SLASH, // encountered opening '/' 41 IS_IN_COMMENT, // within / * * / comment 42 IS_STAR, // encountered closing '*' 43 IS_IN_END_COMMENT // within / / comment 44} input_state_t; 45 46static void usage(char **argv); 47 48int main(int argc, char **argv) 49{ 50 FILE *fp; 51 char bufchar; 52 input_state_t input_state = IS_NORMAL; 53 int exit_code = 0; 54 int remove_whitespace = 0; 55 int arg; 56 57 if(argc < 2) 58 usage(argv); 59 for(arg=2; arg<argc; arg++) { 60 switch(argv[arg][0]) { 61 case 'r': 62 remove_whitespace++; 63 break; 64 default: 65 usage(argv); 66 } 67 } 68 69 fp = fopen(argv[1], "r"); 70 if(!fp) { 71 fprintf(stderr, "Error opening %s\n", argv[1]); 72 perror("fopen"); 73 exit(1); 74 } 75 for(;;) { 76 bufchar = getc_unlocked(fp); 77 if (bufchar == EOF) 78 break; 79 80 switch(input_state) { 81 82 case IS_NORMAL: 83 if(bufchar == '/') { 84 /* 85 * Might be start of a comment. 86 */ 87 input_state = IS_SLASH; 88 } 89 else { 90 if(!(remove_whitespace && isspace(bufchar))) { 91 putchar_unlocked(bufchar); 92 } 93 } 94 break; 95 96 case IS_SLASH: 97 switch(bufchar) { 98 case '*': 99 /* 100 * Start of normal comment. 101 */ 102 input_state = IS_IN_COMMENT; 103 break; 104 105 case '/': 106 /* 107 * Start of 'to-end-of-line' comment. 108 */ 109 input_state = IS_IN_END_COMMENT; 110 break; 111 112 default: 113 /* 114 * Not the start of comment. Emit the '/' 115 * we skipped last char in case we were 116 * entering a comment this time, then the 117 * current char. 118 */ 119 putchar_unlocked('/'); 120 if(!(remove_whitespace && isspace(bufchar))) { 121 putchar_unlocked(bufchar); 122 } 123 input_state = IS_NORMAL; 124 break; 125 } 126 break; 127 128 case IS_IN_COMMENT: 129 if(bufchar == '*') { 130 /* 131 * Maybe ending comment... 132 */ 133 input_state = IS_STAR; 134 } 135 break; 136 137 138 case IS_STAR: 139 switch(bufchar) { 140 case '/': 141 /* 142 * End of normal comment. 143 */ 144 input_state = IS_NORMAL; 145 break; 146 147 case '*': 148 /* 149 * Still could be one char away from end 150 * of comment. 151 */ 152 break; 153 154 default: 155 /* 156 * Still inside comment, no end in sight. 157 */ 158 input_state = IS_IN_COMMENT; 159 break; 160 } 161 break; 162 163 case IS_IN_END_COMMENT: 164 if(bufchar == '\n') { 165 /* 166 * End of comment. Emit the newline if 167 * appropriate. 168 */ 169 if(!remove_whitespace) { 170 putchar_unlocked(bufchar); 171 } 172 input_state = IS_NORMAL; 173 } 174 break; 175 176 } /* switch input_state */ 177 } /* main read loop */ 178 179 /* 180 * Done. 181 */ 182 return(exit_code); 183} 184 185static void usage(char **argv) 186{ 187 printf("usage: %s infile [r(emove whitespace)]\n", argv[0]); 188 exit(1); 189} 190