| 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 | }
|
|---|