[26] | 1 | /*************************************************************************/ |
---|
| 2 | /* */ |
---|
| 3 | /* Get names of classes, attributes and attribute values */ |
---|
| 4 | /* ----------------------------------------------------- */ |
---|
| 5 | /* */ |
---|
| 6 | /*************************************************************************/ |
---|
| 7 | |
---|
| 8 | |
---|
| 9 | #include "defns.i" |
---|
| 10 | #include "types.i" |
---|
| 11 | #include "extern.i" |
---|
| 12 | |
---|
| 13 | #include <sys/types.h> |
---|
| 14 | #include <sys/stat.h> |
---|
| 15 | |
---|
| 16 | |
---|
| 17 | #define Space(s) (s == ' ' || s == '\n' || s == '\t') |
---|
| 18 | #define SkipComment while ( ( c = getc(f) ) != '\n' ) |
---|
| 19 | |
---|
| 20 | char Delimiter; |
---|
| 21 | String CopyString(); |
---|
| 22 | |
---|
| 23 | |
---|
| 24 | |
---|
| 25 | /*************************************************************************/ |
---|
| 26 | /* */ |
---|
| 27 | /* Read a name from file f into string s, setting Delimiter. */ |
---|
| 28 | /* */ |
---|
| 29 | /* - Embedded periods are permitted, but periods followed by space */ |
---|
| 30 | /* characters act as delimiters. */ |
---|
| 31 | /* - Embedded spaces are permitted, but multiple spaces are replaced */ |
---|
| 32 | /* by a single space. */ |
---|
| 33 | /* - Any character can be escaped by '\'. */ |
---|
| 34 | /* - The remainder of a line following '|' is ignored. */ |
---|
| 35 | /* */ |
---|
| 36 | /*************************************************************************/ |
---|
| 37 | |
---|
| 38 | |
---|
| 39 | Boolean ReadName(f, s) |
---|
| 40 | /* --------- */ |
---|
| 41 | FILE *f; |
---|
| 42 | String s; |
---|
| 43 | { |
---|
| 44 | register char *Sp=s; |
---|
| 45 | register int c; |
---|
| 46 | |
---|
| 47 | /* Skip to first non-space character */ |
---|
| 48 | |
---|
| 49 | while ( ( c = getc(f) ) == '|' || Space(c) ) |
---|
| 50 | { |
---|
| 51 | if ( c == '|' ) SkipComment; |
---|
| 52 | } |
---|
| 53 | |
---|
| 54 | /* Return false if no names to read */ |
---|
| 55 | |
---|
| 56 | if ( c == EOF ) |
---|
| 57 | { |
---|
| 58 | Delimiter = EOF; |
---|
| 59 | return false; |
---|
| 60 | } |
---|
| 61 | |
---|
| 62 | /* Read in characters up to the next delimiter */ |
---|
| 63 | |
---|
[33] | 64 | while ( c != ':' && c != ',' && c != '\n' && c != '\r' && c != '|' && c != EOF ) |
---|
[26] | 65 | { |
---|
| 66 | if ( c == '.' ) |
---|
| 67 | { |
---|
| 68 | if ( ( c = getc(f) ) == '|' || Space(c) ) break; |
---|
| 69 | *Sp++ = '.'; |
---|
| 70 | } |
---|
| 71 | |
---|
| 72 | if ( c == '\\' ) |
---|
| 73 | { |
---|
| 74 | c = getc(f); |
---|
| 75 | } |
---|
| 76 | |
---|
| 77 | *Sp++ = c; |
---|
| 78 | |
---|
| 79 | if ( c == ' ' ) |
---|
| 80 | { |
---|
| 81 | while ( ( c = getc(f) ) == ' ' ) |
---|
| 82 | ; |
---|
| 83 | } |
---|
| 84 | else |
---|
| 85 | { |
---|
| 86 | c = getc(f); |
---|
| 87 | } |
---|
| 88 | } |
---|
| 89 | |
---|
| 90 | if ( c == '|' ) SkipComment; |
---|
| 91 | Delimiter = c; |
---|
| 92 | |
---|
| 93 | /* Strip trailing spaces */ |
---|
| 94 | |
---|
| 95 | while ( Space(*(Sp-1)) ) Sp--; |
---|
| 96 | |
---|
| 97 | *Sp++ = '\0'; |
---|
| 98 | return true; |
---|
| 99 | } |
---|
| 100 | |
---|
| 101 | |
---|
| 102 | |
---|
| 103 | /*************************************************************************/ |
---|
| 104 | /* */ |
---|
| 105 | /* Read the names of classes, attributes and legal attribute values. */ |
---|
| 106 | /* On completion, these names are stored in: */ |
---|
| 107 | /* ClassName - class names */ |
---|
| 108 | /* AttName - attribute names */ |
---|
| 109 | /* AttValName - attribute value names */ |
---|
| 110 | /* with: */ |
---|
| 111 | /* MaxAttVal - number of values for each attribute */ |
---|
| 112 | /* */ |
---|
| 113 | /* Other global variables set are: */ |
---|
| 114 | /* MaxAtt - maximum attribute number */ |
---|
| 115 | /* MaxClass - maximum class number */ |
---|
| 116 | /* MaxDiscrVal - maximum discrete values for any attribute */ |
---|
| 117 | /* */ |
---|
| 118 | /* Note: until the number of attributes is known, the name */ |
---|
| 119 | /* information is assembled in local arrays */ |
---|
| 120 | /* */ |
---|
| 121 | /*************************************************************************/ |
---|
| 122 | |
---|
| 123 | |
---|
| 124 | GetNames() |
---|
| 125 | /* --------- */ |
---|
| 126 | { |
---|
| 127 | FILE *Nf, *fopen(); |
---|
| 128 | char Fn[100], Buffer[1000]; |
---|
| 129 | DiscrValue v; |
---|
| 130 | int AttCeiling=100, ClassCeiling=100, ValCeiling; |
---|
| 131 | |
---|
| 132 | /* Open names file */ |
---|
| 133 | |
---|
| 134 | strcpy(Fn, FileName); |
---|
| 135 | strcat(Fn, ".names"); |
---|
| 136 | if ( ! ( Nf = fopen(Fn, "r") ) ) Error(0, Fn, ""); |
---|
| 137 | |
---|
| 138 | /* Get class names from names file */ |
---|
| 139 | |
---|
| 140 | ClassName = (String *) calloc(ClassCeiling, sizeof(String)); |
---|
| 141 | MaxClass = -1; |
---|
| 142 | do |
---|
| 143 | { |
---|
| 144 | ReadName(Nf, Buffer); |
---|
| 145 | |
---|
| 146 | if ( ++MaxClass >= ClassCeiling) |
---|
| 147 | { |
---|
| 148 | ClassCeiling += 100; |
---|
| 149 | ClassName = (String *) realloc(ClassName, ClassCeiling*sizeof(String)); |
---|
| 150 | } |
---|
| 151 | ClassName[MaxClass] = CopyString(Buffer); |
---|
| 152 | } |
---|
| 153 | while ( Delimiter == ',' ); |
---|
| 154 | |
---|
| 155 | /* Get attribute and attribute value names from names file */ |
---|
| 156 | |
---|
| 157 | AttName = (String *) calloc(AttCeiling, sizeof(String)); |
---|
| 158 | MaxAttVal = (DiscrValue *) calloc(AttCeiling, sizeof(DiscrValue)); |
---|
| 159 | AttValName = (String **) calloc(AttCeiling, sizeof(String *)); |
---|
| 160 | SpecialStatus = (char *) malloc(AttCeiling); |
---|
| 161 | |
---|
| 162 | MaxAtt = -1; |
---|
| 163 | while ( ReadName(Nf, Buffer) ) |
---|
| 164 | { |
---|
| 165 | if ( Delimiter != ':' ) Error(1, Buffer, ""); |
---|
| 166 | |
---|
| 167 | if ( ++MaxAtt >= AttCeiling ) |
---|
| 168 | { |
---|
| 169 | AttCeiling += 100; |
---|
| 170 | AttName = (String *) realloc(AttName, AttCeiling*sizeof(String)); |
---|
| 171 | MaxAttVal = (DiscrValue *) realloc(MaxAttVal, AttCeiling*sizeof(DiscrValue)); |
---|
| 172 | AttValName = (String **) realloc(AttValName, AttCeiling*sizeof(String *)); |
---|
| 173 | SpecialStatus = (char *) realloc(SpecialStatus, AttCeiling); |
---|
| 174 | } |
---|
| 175 | |
---|
| 176 | AttName[MaxAtt] = CopyString(Buffer); |
---|
| 177 | SpecialStatus[MaxAtt] = Nil; |
---|
| 178 | MaxAttVal[MaxAtt] = 0; |
---|
| 179 | ValCeiling = 100; |
---|
| 180 | AttValName[MaxAtt] = (String *) calloc(ValCeiling, sizeof(String)); |
---|
| 181 | |
---|
| 182 | do |
---|
| 183 | { |
---|
| 184 | if ( ! ( ReadName(Nf, Buffer) ) ) Error(2, AttName[MaxAtt], ""); |
---|
| 185 | |
---|
| 186 | if ( ++MaxAttVal[MaxAtt] >= ValCeiling ) |
---|
| 187 | { |
---|
| 188 | ValCeiling += 100; |
---|
| 189 | AttValName[MaxAtt] = |
---|
| 190 | (String *) realloc(AttValName[MaxAtt], ValCeiling*sizeof(String)); |
---|
| 191 | } |
---|
| 192 | |
---|
| 193 | AttValName[MaxAtt][MaxAttVal[MaxAtt]] = CopyString(Buffer); |
---|
| 194 | } |
---|
| 195 | while ( Delimiter == ',' ); |
---|
| 196 | |
---|
| 197 | if ( MaxAttVal[MaxAtt] == 1 ) |
---|
| 198 | { |
---|
| 199 | /* Check for special treatment */ |
---|
| 200 | |
---|
| 201 | if ( ! strcmp(Buffer, "continuous") ) |
---|
| 202 | {} |
---|
| 203 | else |
---|
| 204 | if ( ! memcmp(Buffer, "discrete", 8) ) |
---|
| 205 | { |
---|
| 206 | SpecialStatus[MaxAtt] = DISCRETE; |
---|
| 207 | |
---|
| 208 | /* Read max values, reserve space and check MaxDiscrVal */ |
---|
| 209 | |
---|
| 210 | v = atoi(&Buffer[8]); |
---|
| 211 | if ( v < 2 ) |
---|
| 212 | { |
---|
| 213 | printf("** %s: illegal number of discrete values\n", |
---|
| 214 | AttName[MaxAtt]); |
---|
| 215 | exit(1); |
---|
| 216 | } |
---|
| 217 | |
---|
| 218 | AttValName[MaxAtt] = |
---|
| 219 | (String *) realloc(AttValName[MaxAtt], (v+2)*sizeof(String)); |
---|
| 220 | AttValName[MaxAtt][0] = (char *) v; |
---|
| 221 | if ( v > MaxDiscrVal ) MaxDiscrVal = v; |
---|
| 222 | } |
---|
| 223 | else |
---|
| 224 | if ( ! strcmp(Buffer, "ignore") ) |
---|
| 225 | { |
---|
| 226 | SpecialStatus[MaxAtt] = IGNORE; |
---|
| 227 | } |
---|
| 228 | else |
---|
| 229 | { |
---|
| 230 | /* Cannot have only one discrete value for an attribute */ |
---|
| 231 | |
---|
| 232 | Error(3, AttName[MaxAtt], ""); |
---|
| 233 | } |
---|
| 234 | |
---|
| 235 | MaxAttVal[MaxAtt] = 0; |
---|
| 236 | } |
---|
| 237 | else |
---|
| 238 | if ( MaxAttVal[MaxAtt] > MaxDiscrVal ) MaxDiscrVal = MaxAttVal[MaxAtt]; |
---|
| 239 | } |
---|
| 240 | |
---|
| 241 | fclose(Nf); |
---|
| 242 | } |
---|
| 243 | |
---|
| 244 | |
---|
| 245 | |
---|
| 246 | /*************************************************************************/ |
---|
| 247 | /* */ |
---|
| 248 | /* Locate value Val in List[First] to List[Last] */ |
---|
| 249 | /* */ |
---|
| 250 | /*************************************************************************/ |
---|
| 251 | |
---|
| 252 | |
---|
| 253 | int Which(Val, List, First, Last) |
---|
| 254 | /* ----- */ |
---|
| 255 | String Val, List[]; |
---|
| 256 | short First, Last; |
---|
| 257 | { |
---|
| 258 | short n=First; |
---|
| 259 | |
---|
| 260 | while ( n <= Last && strcmp(Val, List[n]) ) n++; |
---|
| 261 | |
---|
| 262 | return ( n <= Last ? n : First-1 ); |
---|
| 263 | } |
---|
| 264 | |
---|
| 265 | |
---|
| 266 | |
---|
| 267 | /*************************************************************************/ |
---|
| 268 | /* */ |
---|
| 269 | /* Allocate space then copy string into it */ |
---|
| 270 | /* */ |
---|
| 271 | /*************************************************************************/ |
---|
| 272 | |
---|
| 273 | String CopyString(x) |
---|
| 274 | /* ----------- */ |
---|
| 275 | String x; |
---|
| 276 | { |
---|
| 277 | char *s; |
---|
| 278 | |
---|
| 279 | s = (char *) calloc(strlen(x)+1, sizeof(char)); |
---|
| 280 | strcpy(s, x); |
---|
| 281 | return s; |
---|
| 282 | } |
---|
| 283 | |
---|
| 284 | |
---|
| 285 | |
---|
| 286 | /*************************************************************************/ |
---|
| 287 | /* */ |
---|
| 288 | /* Error messages */ |
---|
| 289 | /* */ |
---|
| 290 | /*************************************************************************/ |
---|
| 291 | |
---|
| 292 | Error(n, s1, s2) |
---|
| 293 | /* ----- */ |
---|
| 294 | short n; |
---|
| 295 | String s1, s2; |
---|
| 296 | { |
---|
| 297 | static char Messages=0; |
---|
| 298 | |
---|
| 299 | printf("\nERROR: "); |
---|
| 300 | switch(n) |
---|
| 301 | { |
---|
| 302 | case 0: printf("cannot open file %s%s\n", s1, s2); |
---|
| 303 | exit(1); |
---|
| 304 | |
---|
| 305 | case 1: printf("colon expected after attribute name %s\n", s1); |
---|
| 306 | break; |
---|
| 307 | |
---|
| 308 | case 2: printf("unexpected eof while reading attribute %s\n", s1); |
---|
| 309 | break; |
---|
| 310 | |
---|
| 311 | case 3: printf("attribute %s has only one value\n", s1); |
---|
| 312 | break; |
---|
| 313 | |
---|
| 314 | case 4: printf("case %d's value of '%s' for attribute %s is illegal\n", |
---|
| 315 | MaxItem+1, s2, s1); |
---|
| 316 | break; |
---|
| 317 | |
---|
| 318 | case 5: printf("case %d's class of '%s' is illegal\n", MaxItem+1, s2); |
---|
| 319 | } |
---|
| 320 | |
---|
| 321 | if ( ++Messages > 10 ) |
---|
| 322 | { |
---|
| 323 | printf("Error limit exceeded\n"); |
---|
| 324 | exit(1); |
---|
| 325 | } |
---|
| 326 | } |
---|