| 1 | /* emxcat.c -- Concatenate source files | 
|---|
| 2 | Copyright (c) 1992-1998 Eberhard Mattes | 
|---|
| 3 |  | 
|---|
| 4 | This file is part of emxcat. | 
|---|
| 5 |  | 
|---|
| 6 | emxcat is free software; you can redistribute it and/or modify it | 
|---|
| 7 | under the terms of the GNU General Public License as published by | 
|---|
| 8 | the Free Software Foundation; either version 2, or (at your option) | 
|---|
| 9 | any later version. | 
|---|
| 10 |  | 
|---|
| 11 | emxcat is distributed in the hope that it will be useful, | 
|---|
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
| 14 | GNU General Public License for more details. | 
|---|
| 15 |  | 
|---|
| 16 | You should have received a copy of the GNU General Public License | 
|---|
| 17 | along with emxcat; see the file COPYING.  If not, write to | 
|---|
| 18 | the Free Software Foundation, 59 Temple Place - Suite 330, | 
|---|
| 19 | Boston, MA 02111-1307, USA.  */ | 
|---|
| 20 |  | 
|---|
| 21 |  | 
|---|
| 22 | #include <stdio.h> | 
|---|
| 23 | #include <stdlib.h> | 
|---|
| 24 | #include <string.h> | 
|---|
| 25 | #include <ctype.h> | 
|---|
| 26 |  | 
|---|
| 27 | #define NORETURN volatile | 
|---|
| 28 |  | 
|---|
| 29 | #define FALSE 0 | 
|---|
| 30 | #define TRUE  1 | 
|---|
| 31 |  | 
|---|
| 32 | typedef struct list | 
|---|
| 33 | { | 
|---|
| 34 | struct list *next; | 
|---|
| 35 | char *name; | 
|---|
| 36 | } list; | 
|---|
| 37 |  | 
|---|
| 38 | typedef struct edge | 
|---|
| 39 | { | 
|---|
| 40 | struct edge *next; | 
|---|
| 41 | struct vertex *v; | 
|---|
| 42 | } edge; | 
|---|
| 43 |  | 
|---|
| 44 | typedef struct vertex | 
|---|
| 45 | { | 
|---|
| 46 | struct vertex *next; | 
|---|
| 47 | edge *desc; | 
|---|
| 48 | char *name; | 
|---|
| 49 | int mark; | 
|---|
| 50 | int number; | 
|---|
| 51 | int descs; | 
|---|
| 52 | } vertex; | 
|---|
| 53 |  | 
|---|
| 54 | static vertex *includes = NULL; | 
|---|
| 55 | static vertex **includes_add = &includes; | 
|---|
| 56 | static vertex *prev_include = NULL; | 
|---|
| 57 | static list *selects = NULL; | 
|---|
| 58 | static list **selects_add = &selects; | 
|---|
| 59 | static list *consts = NULL; | 
|---|
| 60 | static list **consts_add = &consts; | 
|---|
| 61 | static list *defines; | 
|---|
| 62 | static list **defines_add; | 
|---|
| 63 | static list *predefs = NULL; | 
|---|
| 64 | static list **predefs_add = &predefs; | 
|---|
| 65 | static char *output_fname; | 
|---|
| 66 | static FILE *output_file; | 
|---|
| 67 | static int rc = 0; | 
|---|
| 68 | static int define_warning; | 
|---|
| 69 | static int sys_emx_h = FALSE; | 
|---|
| 70 |  | 
|---|
| 71 |  | 
|---|
| 72 | /* Prototypes. */ | 
|---|
| 73 |  | 
|---|
| 74 | static void NORETURN usage (void); | 
|---|
| 75 | static void *xmalloc (size_t n); | 
|---|
| 76 | static char *xstrdup (const char *s); | 
|---|
| 77 | int main (int argc, char *argv[]); | 
|---|
| 78 |  | 
|---|
| 79 |  | 
|---|
| 80 | /* Tell the user how to invoke this program. */ | 
|---|
| 81 |  | 
|---|
| 82 | static void NORETURN usage (void) | 
|---|
| 83 | { | 
|---|
| 84 | fprintf (stderr, "emxcat " VERSION INNOTEK_VERSION " -- " | 
|---|
| 85 | "Copyright (c) 1992-1995 by Eberhard Mattes\n\n"); | 
|---|
| 86 | fprintf (stderr, "Usage: emxcat [-D<symbol>]... -o <output_file> <input_file>...\n"); | 
|---|
| 87 | exit (1); | 
|---|
| 88 | } | 
|---|
| 89 |  | 
|---|
| 90 |  | 
|---|
| 91 | /* Allocate a block of memory.  Abort if out of memory. */ | 
|---|
| 92 |  | 
|---|
| 93 | static void *xmalloc (size_t n) | 
|---|
| 94 | { | 
|---|
| 95 | void *p; | 
|---|
| 96 |  | 
|---|
| 97 | p = malloc (n); | 
|---|
| 98 | if (p == NULL) | 
|---|
| 99 | { | 
|---|
| 100 | fprintf (stderr, "emxcat: out of memory\n"); | 
|---|
| 101 | exit (2); | 
|---|
| 102 | } | 
|---|
| 103 | return p; | 
|---|
| 104 | } | 
|---|
| 105 |  | 
|---|
| 106 |  | 
|---|
| 107 | /* Create on the heap a duplicate of the string S.  Abort if out of | 
|---|
| 108 | memory. */ | 
|---|
| 109 |  | 
|---|
| 110 | static char *xstrdup (const char *s) | 
|---|
| 111 | { | 
|---|
| 112 | char *p; | 
|---|
| 113 |  | 
|---|
| 114 | p = xmalloc (strlen (s) + 1); | 
|---|
| 115 | strcpy (p, s); | 
|---|
| 116 | return p; | 
|---|
| 117 | } | 
|---|
| 118 |  | 
|---|
| 119 |  | 
|---|
| 120 | /* Add a string to a linked to list of strings. */ | 
|---|
| 121 |  | 
|---|
| 122 | static void add_list (list ***dst, const char *src) | 
|---|
| 123 | { | 
|---|
| 124 | list *p; | 
|---|
| 125 |  | 
|---|
| 126 | p = xmalloc (sizeof (*p)); | 
|---|
| 127 | p->next = NULL; | 
|---|
| 128 | p->name = (char *)src; | 
|---|
| 129 | **dst = p; | 
|---|
| 130 | *dst = &p->next; | 
|---|
| 131 | } | 
|---|
| 132 |  | 
|---|
| 133 |  | 
|---|
| 134 | /* Handle an #include directive. */ | 
|---|
| 135 |  | 
|---|
| 136 | static int do_include (const char *str, int pass, const char *fname) | 
|---|
| 137 | { | 
|---|
| 138 | char delim; | 
|---|
| 139 | char *name; | 
|---|
| 140 | int len; | 
|---|
| 141 | const char *start, *s; | 
|---|
| 142 | vertex *p, *v; | 
|---|
| 143 | edge *e; | 
|---|
| 144 |  | 
|---|
| 145 | if (pass == 1 && defines != NULL && !define_warning) | 
|---|
| 146 | { | 
|---|
| 147 | fprintf (stderr, "emxcat: #define used before #include in %s\n", | 
|---|
| 148 | fname); | 
|---|
| 149 | define_warning = TRUE; | 
|---|
| 150 | rc = 1; | 
|---|
| 151 | } | 
|---|
| 152 | s = str; | 
|---|
| 153 | if (!isspace ((unsigned char)*s)) | 
|---|
| 154 | return TRUE; | 
|---|
| 155 | while (isspace ((unsigned char)*s)) | 
|---|
| 156 | ++s; | 
|---|
| 157 | if (*s == '"') | 
|---|
| 158 | delim = '"'; | 
|---|
| 159 | else if (*s == '<') | 
|---|
| 160 | delim = '>'; | 
|---|
| 161 | else | 
|---|
| 162 | return TRUE; | 
|---|
| 163 | start = s; | 
|---|
| 164 | ++s; | 
|---|
| 165 | while (*s != 0 && *s != delim) | 
|---|
| 166 | ++s; | 
|---|
| 167 | if (*s != delim) | 
|---|
| 168 | return TRUE; | 
|---|
| 169 | if (pass == 1) | 
|---|
| 170 | return FALSE; | 
|---|
| 171 | ++s; | 
|---|
| 172 | len = s - start; | 
|---|
| 173 | name = alloca (len+1); | 
|---|
| 174 | memcpy (name, start, len); | 
|---|
| 175 | name[len] = 0; | 
|---|
| 176 | if (strcmp (name, "<sys/emx.h>") == 0) | 
|---|
| 177 | { | 
|---|
| 178 | sys_emx_h = TRUE; | 
|---|
| 179 | return FALSE; | 
|---|
| 180 | } | 
|---|
| 181 | v = NULL; | 
|---|
| 182 | for (p = includes; p != NULL; p = p->next) | 
|---|
| 183 | if (strcmp (name, p->name) == 0) | 
|---|
| 184 | { | 
|---|
| 185 | v = p; | 
|---|
| 186 | break; | 
|---|
| 187 | } | 
|---|
| 188 | if (v == NULL) | 
|---|
| 189 | { | 
|---|
| 190 | v = xmalloc (sizeof (*v)); | 
|---|
| 191 | v->next = NULL; | 
|---|
| 192 | v->name = xstrdup (name); | 
|---|
| 193 | v->desc = NULL; | 
|---|
| 194 | v->mark = 0; | 
|---|
| 195 | v->descs = 0; | 
|---|
| 196 | *includes_add = v; | 
|---|
| 197 | includes_add = &v->next; | 
|---|
| 198 | } | 
|---|
| 199 | if (prev_include != NULL) | 
|---|
| 200 | { | 
|---|
| 201 | for (e = v->desc; e != NULL; e = e->next) | 
|---|
| 202 | if (e->v == prev_include) | 
|---|
| 203 | break; | 
|---|
| 204 | if (e == NULL) | 
|---|
| 205 | { | 
|---|
| 206 | e = xmalloc (sizeof (*e)); | 
|---|
| 207 | e->next = v->desc; | 
|---|
| 208 | v->desc = e; | 
|---|
| 209 | e->v = prev_include; | 
|---|
| 210 | } | 
|---|
| 211 | } | 
|---|
| 212 | prev_include = v; | 
|---|
| 213 | return FALSE; | 
|---|
| 214 | } | 
|---|
| 215 |  | 
|---|
| 216 |  | 
|---|
| 217 | /* Handle a #define directive. */ | 
|---|
| 218 |  | 
|---|
| 219 | static int do_define (const char *str, int pass) | 
|---|
| 220 | { | 
|---|
| 221 | char *name; | 
|---|
| 222 | int len; | 
|---|
| 223 | const char *start, *s; | 
|---|
| 224 | list *p; | 
|---|
| 225 |  | 
|---|
| 226 | s = str; | 
|---|
| 227 | if (!isspace ((unsigned char)*s)) | 
|---|
| 228 | return TRUE; | 
|---|
| 229 | while (isspace ((unsigned char)*s)) | 
|---|
| 230 | ++s; | 
|---|
| 231 | start = s; | 
|---|
| 232 | while (*s == '_' || isalnum ((unsigned char)*s)) | 
|---|
| 233 | ++s; | 
|---|
| 234 | len = s - start; | 
|---|
| 235 | name = alloca (len+1); | 
|---|
| 236 | memcpy (name, start, len); | 
|---|
| 237 | name[len] = 0; | 
|---|
| 238 | while (isspace ((unsigned char)*s)) | 
|---|
| 239 | ++s; | 
|---|
| 240 | if (strncmp (s, "/*", 2) == 0) | 
|---|
| 241 | s = strchr (s, 0); | 
|---|
| 242 | if (strncmp (name, "INCL_", 5) == 0 && *s == 0) | 
|---|
| 243 | { | 
|---|
| 244 | if (pass == 1) | 
|---|
| 245 | return FALSE; | 
|---|
| 246 | for (p = selects; p != NULL; p = p->next) | 
|---|
| 247 | if (strcmp (p->name, name) == 0) | 
|---|
| 248 | return FALSE; | 
|---|
| 249 | add_list (&selects_add, xstrdup (name)); | 
|---|
| 250 | return FALSE; | 
|---|
| 251 | } | 
|---|
| 252 | else if (pass == 0) | 
|---|
| 253 | return FALSE; | 
|---|
| 254 | else | 
|---|
| 255 | { | 
|---|
| 256 | add_list (&defines_add, xstrdup (name)); | 
|---|
| 257 | return TRUE; | 
|---|
| 258 | } | 
|---|
| 259 | } | 
|---|
| 260 |  | 
|---|
| 261 |  | 
|---|
| 262 | /* Handle a CONST_ definition encountered in an .s file. */ | 
|---|
| 263 |  | 
|---|
| 264 | static int do_const (const char *str, int pass) | 
|---|
| 265 | { | 
|---|
| 266 | const char *s; | 
|---|
| 267 | char *name; | 
|---|
| 268 | int len; | 
|---|
| 269 | list *p; | 
|---|
| 270 |  | 
|---|
| 271 | if (pass == 0) | 
|---|
| 272 | return FALSE; | 
|---|
| 273 | for (s = str; *s == '_' || isalnum ((unsigned char)*s); ++s) | 
|---|
| 274 | ; | 
|---|
| 275 | len = s - str; | 
|---|
| 276 | name = alloca (len+1); | 
|---|
| 277 | memcpy (name, str, len); | 
|---|
| 278 | name[len] = 0; | 
|---|
| 279 | for (p = consts; p != NULL; p = p->next) | 
|---|
| 280 | if (strcmp (name, p->name) == 0) | 
|---|
| 281 | return FALSE; | 
|---|
| 282 | add_list (&consts_add, xstrdup (name)); | 
|---|
| 283 | return TRUE; | 
|---|
| 284 | } | 
|---|
| 285 |  | 
|---|
| 286 |  | 
|---|
| 287 | /* Clear all marks of the dag of header files. */ | 
|---|
| 288 |  | 
|---|
| 289 | static void unmark (void) | 
|---|
| 290 | { | 
|---|
| 291 | vertex *p; | 
|---|
| 292 |  | 
|---|
| 293 | for (p = includes; p != NULL; p = p->next) | 
|---|
| 294 | p->mark = 0; | 
|---|
| 295 | } | 
|---|
| 296 |  | 
|---|
| 297 |  | 
|---|
| 298 | /* Number the vertices of the dag of header files. */ | 
|---|
| 299 |  | 
|---|
| 300 | static int vn; | 
|---|
| 301 |  | 
|---|
| 302 | static void number_2 (vertex *v) | 
|---|
| 303 | { | 
|---|
| 304 | edge *e; | 
|---|
| 305 |  | 
|---|
| 306 | v->mark = 1; | 
|---|
| 307 | v->number = vn++; | 
|---|
| 308 | v->descs = 0; | 
|---|
| 309 | for (e = v->desc; e != NULL; e = e->next) | 
|---|
| 310 | if (!e->v->mark) | 
|---|
| 311 | { | 
|---|
| 312 | number_2 (e->v); | 
|---|
| 313 | v->descs += 1 + e->v->descs; | 
|---|
| 314 | } | 
|---|
| 315 | } | 
|---|
| 316 |  | 
|---|
| 317 | /* Helper function for checking for cycles the dag of header files. */ | 
|---|
| 318 |  | 
|---|
| 319 | static void cycles_2 (vertex *v, const char *fname) | 
|---|
| 320 | { | 
|---|
| 321 | edge *e; | 
|---|
| 322 | vertex *w; | 
|---|
| 323 |  | 
|---|
| 324 | v->mark = 1; | 
|---|
| 325 | for (e = v->desc; e != NULL; e = e->next) | 
|---|
| 326 | { | 
|---|
| 327 | w = e->v; | 
|---|
| 328 | if (w->mark) | 
|---|
| 329 | { | 
|---|
| 330 | if (v->number >= w->number && v->number <= w->number + w->descs) | 
|---|
| 331 | { | 
|---|
| 332 | fprintf (stderr, "emxcat: %s: inconsistent order of %s and %s\n", | 
|---|
| 333 | fname, v->name, w->name); | 
|---|
| 334 | rc = 1; | 
|---|
| 335 | } | 
|---|
| 336 | } | 
|---|
| 337 | else | 
|---|
| 338 | cycles_2 (w, fname); | 
|---|
| 339 | } | 
|---|
| 340 | } | 
|---|
| 341 |  | 
|---|
| 342 | /* Check for cycles the dag of header files. */ | 
|---|
| 343 |  | 
|---|
| 344 | static void cycles (const char *fname) | 
|---|
| 345 | { | 
|---|
| 346 | vertex *p; | 
|---|
| 347 |  | 
|---|
| 348 | unmark (); | 
|---|
| 349 | vn = 1; | 
|---|
| 350 | for (p = includes; p != NULL; p = p->next) | 
|---|
| 351 | if (!p->mark) | 
|---|
| 352 | number_2 (p); | 
|---|
| 353 | unmark (); | 
|---|
| 354 | for (p = includes; p != NULL; p = p->next) | 
|---|
| 355 | if (!p->mark) | 
|---|
| 356 | cycles_2 (p, fname); | 
|---|
| 357 | } | 
|---|
| 358 |  | 
|---|
| 359 |  | 
|---|
| 360 | /* Read the input file named FNAME.  If PASS is zero, collect | 
|---|
| 361 | information.  If PASS is one, copy the file contents to the output | 
|---|
| 362 | file. */ | 
|---|
| 363 |  | 
|---|
| 364 | static void read_file (const char *fname, int pass) | 
|---|
| 365 | { | 
|---|
| 366 | FILE *f; | 
|---|
| 367 | char *s; | 
|---|
| 368 | list *p, *q; | 
|---|
| 369 | enum {TYPE_UNKNOWN, TYPE_C, TYPE_S} type; | 
|---|
| 370 | char line[1024]; | 
|---|
| 371 | int copy; | 
|---|
| 372 |  | 
|---|
| 373 | /* Determine the type of the file (C or assembler) from the file | 
|---|
| 374 | name suffix. */ | 
|---|
| 375 |  | 
|---|
| 376 | type = TYPE_UNKNOWN; | 
|---|
| 377 | s = _getext (fname); | 
|---|
| 378 | if (s != NULL) | 
|---|
| 379 | { | 
|---|
| 380 | ++s; | 
|---|
| 381 | if (stricmp (s, "c") == 0 || stricmp (s, "cc") == 0 | 
|---|
| 382 | || stricmp (s, "cpp") == 0 || stricmp (s, "cxx") == 0) | 
|---|
| 383 | type = TYPE_C; | 
|---|
| 384 | else if (stricmp (s, "s") == 0) | 
|---|
| 385 | type = TYPE_S; | 
|---|
| 386 | } | 
|---|
| 387 |  | 
|---|
| 388 | /* Abort if the file type is not known. */ | 
|---|
| 389 |  | 
|---|
| 390 | if (type == TYPE_UNKNOWN) | 
|---|
| 391 | { | 
|---|
| 392 | fprintf (stderr, "emxcat: unknown file type (%s)\n", fname); | 
|---|
| 393 | exit (1); | 
|---|
| 394 | } | 
|---|
| 395 |  | 
|---|
| 396 | /* Open the file. */ | 
|---|
| 397 |  | 
|---|
| 398 | f = fopen (fname, "rt"); | 
|---|
| 399 | if (f == NULL) | 
|---|
| 400 | { | 
|---|
| 401 | perror (fname); | 
|---|
| 402 | exit (2); | 
|---|
| 403 | } | 
|---|
| 404 |  | 
|---|
| 405 | /* Initialize file-local variables. */ | 
|---|
| 406 |  | 
|---|
| 407 | defines = NULL; defines_add = &defines; prev_include = NULL; | 
|---|
| 408 | define_warning = FALSE; | 
|---|
| 409 |  | 
|---|
| 410 | /* Read lines until hitting the end of the file. */ | 
|---|
| 411 |  | 
|---|
| 412 | while (fgets (line, sizeof (line), f) != NULL) | 
|---|
| 413 | { | 
|---|
| 414 | /* Lines starting with #include and #define are handled | 
|---|
| 415 | specially.  In assembler files, lines starting with CONST_ | 
|---|
| 416 | are handled specially.  In the second pass, all other lines | 
|---|
| 417 | are copied verbatim to the output file. */ | 
|---|
| 418 |  | 
|---|
| 419 | if (memcmp (line, "#include", 8) == 0) | 
|---|
| 420 | copy = do_include (line+8, pass, fname); | 
|---|
| 421 | else if (type == TYPE_S && memcmp (line, "CONST_", 6) == 0) | 
|---|
| 422 | copy = do_const (line, pass); | 
|---|
| 423 | else if (memcmp (line, "#define", 7) == 0) | 
|---|
| 424 | copy = do_define (line+7, pass); | 
|---|
| 425 | else | 
|---|
| 426 | copy = TRUE; | 
|---|
| 427 |  | 
|---|
| 428 | /* Write the line to the output file if we are in the second | 
|---|
| 429 | pass and the line is to be copied. */ | 
|---|
| 430 |  | 
|---|
| 431 | if (copy && pass == 1) | 
|---|
| 432 | { | 
|---|
| 433 | if (fputs (line, output_file) == EOF) | 
|---|
| 434 | break; | 
|---|
| 435 | } | 
|---|
| 436 | } | 
|---|
| 437 |  | 
|---|
| 438 | /* Check the input stream for I/O errors, then close it. */ | 
|---|
| 439 |  | 
|---|
| 440 | if (ferror (f)) | 
|---|
| 441 | { | 
|---|
| 442 | perror (fname); | 
|---|
| 443 | exit (2); | 
|---|
| 444 | } | 
|---|
| 445 | fclose (f); | 
|---|
| 446 |  | 
|---|
| 447 | /* Undefine all symbols #defined in this file. */ | 
|---|
| 448 |  | 
|---|
| 449 | if (defines != NULL) | 
|---|
| 450 | { | 
|---|
| 451 | fputc ('\n', output_file); | 
|---|
| 452 | for (p = defines; p != NULL; p = q) | 
|---|
| 453 | { | 
|---|
| 454 | q = p->next; | 
|---|
| 455 | fprintf (output_file, "#undef %s\n", p->name); | 
|---|
| 456 | free (p->name); | 
|---|
| 457 | free (p); | 
|---|
| 458 | } | 
|---|
| 459 | } | 
|---|
| 460 |  | 
|---|
| 461 | /* Check for cycles the dag of header files. */ | 
|---|
| 462 |  | 
|---|
| 463 | if (pass == 0) | 
|---|
| 464 | cycles (fname); | 
|---|
| 465 |  | 
|---|
| 466 | /* In the second pass, write an empty line to the output file, and | 
|---|
| 467 | check for I/O errors. */ | 
|---|
| 468 |  | 
|---|
| 469 | if (pass == 1) | 
|---|
| 470 | { | 
|---|
| 471 | fputc ('\n', output_file); | 
|---|
| 472 | if (ferror (output_file)) | 
|---|
| 473 | { | 
|---|
| 474 | perror ("emxcat output file"); | 
|---|
| 475 | exit (2); | 
|---|
| 476 | } | 
|---|
| 477 | } | 
|---|
| 478 | } | 
|---|
| 479 |  | 
|---|
| 480 |  | 
|---|
| 481 | /* Write #define directives for predefined symbols. */ | 
|---|
| 482 |  | 
|---|
| 483 | static void insert_predefs (void) | 
|---|
| 484 | { | 
|---|
| 485 | list *p; | 
|---|
| 486 |  | 
|---|
| 487 | for (p = predefs; p != NULL; p = p->next) | 
|---|
| 488 | fprintf (output_file, "#define %s\n", p->name); | 
|---|
| 489 | } | 
|---|
| 490 |  | 
|---|
| 491 |  | 
|---|
| 492 | /* Insert #define directives which have been used before #include | 
|---|
| 493 | directives. */ | 
|---|
| 494 |  | 
|---|
| 495 | static void insert_selects (void) | 
|---|
| 496 | { | 
|---|
| 497 | list *p; | 
|---|
| 498 |  | 
|---|
| 499 | for (p = selects; p != NULL; p = p->next) | 
|---|
| 500 | fprintf (output_file, "#define %s\n", p->name); | 
|---|
| 501 | } | 
|---|
| 502 |  | 
|---|
| 503 |  | 
|---|
| 504 | /* Topological sort on the dag of #include directives, writing them to | 
|---|
| 505 | the output file. */ | 
|---|
| 506 |  | 
|---|
| 507 | static void insert_includes_2 (vertex *v) | 
|---|
| 508 | { | 
|---|
| 509 | edge *e; | 
|---|
| 510 |  | 
|---|
| 511 | v->mark = 1; | 
|---|
| 512 | for (e = v->desc; e != NULL; e = e->next) | 
|---|
| 513 | if (!e->v->mark) | 
|---|
| 514 | insert_includes_2 (e->v); | 
|---|
| 515 | fprintf (output_file, "#include %s\n", v->name); | 
|---|
| 516 | } | 
|---|
| 517 |  | 
|---|
| 518 |  | 
|---|
| 519 | /* Compare two argv[] entries by name.  This function is passed to | 
|---|
| 520 | qsort() for sorting the input files by name. */ | 
|---|
| 521 |  | 
|---|
| 522 | int cmp_fname (const void *p1, const void *p2) | 
|---|
| 523 | { | 
|---|
| 524 | /* Disregard case when comparing file names, to get same result on | 
|---|
| 525 | case-preserving file systems (HPFS) and upper-casing file systems | 
|---|
| 526 | (FAT). */ | 
|---|
| 527 |  | 
|---|
| 528 | return strcasecmp (*(const char * const *)p1, | 
|---|
| 529 | *(const char * const *)p2); | 
|---|
| 530 | } | 
|---|
| 531 |  | 
|---|
| 532 |  | 
|---|
| 533 | /* Topologically sort #include directives and write them to the output | 
|---|
| 534 | file.  <sys/emx.h> always comes first. */ | 
|---|
| 535 |  | 
|---|
| 536 | static void insert_includes (void) | 
|---|
| 537 | { | 
|---|
| 538 | vertex *p; | 
|---|
| 539 |  | 
|---|
| 540 | if (sys_emx_h) | 
|---|
| 541 | fputs ("#include <sys/emx.h>\n", output_file); | 
|---|
| 542 | unmark (); | 
|---|
| 543 | for (p = includes; p != NULL; p = p->next) | 
|---|
| 544 | if (!p->mark) | 
|---|
| 545 | insert_includes_2 (p); | 
|---|
| 546 | } | 
|---|
| 547 |  | 
|---|
| 548 |  | 
|---|
| 549 | /* The main code of emxcat. */ | 
|---|
| 550 |  | 
|---|
| 551 | int main (int argc, char *argv[]) | 
|---|
| 552 | { | 
|---|
| 553 | int i, j, pass; | 
|---|
| 554 |  | 
|---|
| 555 | /* Expand response files and wildcards. */ | 
|---|
| 556 |  | 
|---|
| 557 | _response (&argc, &argv); | 
|---|
| 558 | _wildcard (&argc, &argv); | 
|---|
| 559 |  | 
|---|
| 560 | /* Handle -D options. */ | 
|---|
| 561 |  | 
|---|
| 562 | i = 1; | 
|---|
| 563 | while (i < argc && strncmp (argv[i], "-D", 2) == 0 && strlen (argv[i]) > 2) | 
|---|
| 564 | { | 
|---|
| 565 | add_list (&predefs_add, xstrdup (argv[i] + 2)); | 
|---|
| 566 | ++i; | 
|---|
| 567 | } | 
|---|
| 568 |  | 
|---|
| 569 | /* 3 or more arguments must be left: -o <output_file> <input_file> */ | 
|---|
| 570 |  | 
|---|
| 571 | if (argc - i < 3) | 
|---|
| 572 | usage (); | 
|---|
| 573 | if (strcmp (argv[i], "-o") != 0) | 
|---|
| 574 | usage (); | 
|---|
| 575 | ++i; | 
|---|
| 576 | output_fname = argv[i++]; | 
|---|
| 577 |  | 
|---|
| 578 | /* Open the output file. */ | 
|---|
| 579 |  | 
|---|
| 580 | output_file = fopen (output_fname, "wt"); | 
|---|
| 581 | if (output_file == NULL) | 
|---|
| 582 | { | 
|---|
| 583 | perror (output_fname); | 
|---|
| 584 | exit (2); | 
|---|
| 585 | } | 
|---|
| 586 |  | 
|---|
| 587 | /* Sort the input files by name.  This is for getting predictable | 
|---|
| 588 | results when using wildcards.  Note that _wildcard() yields files | 
|---|
| 589 | sorted by name on HPFS partitions.  On FAT partitions, however, | 
|---|
| 590 | the files are not in a particular order. */ | 
|---|
| 591 |  | 
|---|
| 592 | qsort (argv + i, argc - i, sizeof (*argv), cmp_fname); | 
|---|
| 593 |  | 
|---|
| 594 | /* Make two passes over all the files.  The first pass collects | 
|---|
| 595 | information, the second pass writes the output file. */ | 
|---|
| 596 |  | 
|---|
| 597 | for (pass = 0; pass < 2; ++pass) | 
|---|
| 598 | { | 
|---|
| 599 | if (pass == 1) | 
|---|
| 600 | { | 
|---|
| 601 | /* At the beginning of the second pass, write #define and | 
|---|
| 602 | #include directives. */ | 
|---|
| 603 |  | 
|---|
| 604 | insert_predefs (); | 
|---|
| 605 | insert_selects (); | 
|---|
| 606 | insert_includes (); | 
|---|
| 607 | } | 
|---|
| 608 |  | 
|---|
| 609 | /* Read each input file given on the command line, provided its | 
|---|
| 610 | name is not identical to the name of the output file. */ | 
|---|
| 611 |  | 
|---|
| 612 | for (j = i; j < argc; ++j) | 
|---|
| 613 | if (strcasecmp (output_fname, argv[j]) != 0) | 
|---|
| 614 | read_file (argv[j], pass); | 
|---|
| 615 | } | 
|---|
| 616 |  | 
|---|
| 617 | /* Close the output file. */ | 
|---|
| 618 |  | 
|---|
| 619 | if (fflush (output_file) != 0 || fclose (output_file) != 0) | 
|---|
| 620 | { | 
|---|
| 621 | perror (output_fname); | 
|---|
| 622 | exit (2); | 
|---|
| 623 | } | 
|---|
| 624 |  | 
|---|
| 625 | /* Done. */ | 
|---|
| 626 |  | 
|---|
| 627 | return rc; | 
|---|
| 628 | } | 
|---|