Annotation of coherent/b/STREAMS/conf/bin/src/mklink.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Create a compile/link manifest for the system kernel based on the
                      3:  * configured devices and the presence of files in the configuration
                      4:  * directories.
                      5:  */
                      6: 
                      7: /*
                      8:  *-IMPORTS:
                      9:  *     <sys/compat.h>
                     10:  *             CONST
                     11:  *             USE_PROTO
                     12:  *             ARGS ()
                     13:  *     <stdio.h>
                     14:  *             NULL
                     15:  *             stdin
                     16:  *             stdout
                     17:  *             fopen ()
                     18:  *             fclose ()
                     19:  *             fputs ()
                     20:  *             fputc ()
                     21:  *     <stdlib.h>
                     22:  *             getenv ()
                     23:  *     <time.h>
                     24:  *             time_t
                     25:  *             localtime ()
                     26:  *             time ()
                     27:  *     <string.h>
                     28:  *             strerror ()
                     29:  *             strftime ()
                     30:  *     "ehand.h"
                     31:  *             ehand_t
                     32:  *             PUSH_HANDLER ()
                     33:  *             POP_HANDLER ()
                     34:  *             CHAIN_ERROR ()
                     35:  *             throw_error ()
                     36:  *     "buildobj.h"
                     37:  *             build_t
                     38:  *             builder_alloc ()
                     39:  *             builder_free ()
                     40:  *             build_begin ()
                     41:  *             build_add ()
                     42:  *             build_end ()
                     43:  *             build_release ()
                     44:  *             build_error ()
                     45:  *     "mdev.h"
                     46:  *             MD_ENABLED
                     47:  *             mdev_t
                     48:  *             miter_t
                     49:  *             for_all_mdevices ()
                     50:  *     "symbol.h"
                     51:  *             symbol_t
                     52:  *     "read.h"
                     53:  *             READ_EOF
                     54:  *             input_t
                     55:  *             read_char ()
                     56:  *             read_error ()
                     57:  *             read_close ()
                     58:  *     "mkinput.h"
                     59:  *             make_file_input ()
                     60:  */
                     61: 
                     62: #include <sys/compat.h>
                     63: #include <stdio.h>
                     64: #include <stdlib.h>
                     65: #include <time.h>
                     66: #include <string.h>
                     67: #include <errno.h>
                     68: 
                     69: #include "ehand.h"
                     70: #include "buildobj.h"
                     71: #include "mdev.h"
                     72: #include "symbol.h"
                     73: #include "read.h"
                     74: #include "mkinput.h"
                     75: 
                     76: #include "mkconf.h"
                     77: 
                     78: /*
                     79:  * For entries that are OS-specific, wrap up the choice in a macro.
                     80:  */
                     81: 
                     82: #ifdef __MSDOS__
                     83: 
                     84: #define        DOS_OR_UNIX(dos,unix)   dos
                     85: 
                     86: #else
                     87: 
                     88: #define        DOS_OR_UNIX(dos, unix)  unix
                     89: 
                     90: #endif
                     91: 
                     92: 
                     93: /*
                     94:  * Testing for the existence of a file may seem simple, but there are some
                     95:  * subtleties that can trip the unwary, such as which function to use to test
                     96:  * for the existence of the object?
                     97:  *
                     98:  *  + fopen () is in ISO C and checks for (a) existence of the named object,
                     99:  *    (b) whether it is readable. It may return a useful value in 'errno'
                    100:  *    which can be used to (i) issue diagnostics in the user's local language,
                    101:  *    (ii) cope with specific kinds of error gracefully, since support for an
                    102:  *    E... code defined in an extension to C library behaviour such as POSIX.1
                    103:  *    can be tested for with the #ifdef directive.
                    104:  *  - fopen () can be slow.
                    105:  *
                    106:  *  + access () can test quickly for readability and existence, is present in
                    107:  *    POSIX.1.
                    108:  *  - access () isn't in ISO C, and some older Unix systems do things rather
                    109:  *    differently than POSIX specifies.
                    110:  *
                    111:  *  + fstat () returns all the information that access () does, and more. It
                    112:  *    is older and more likely to be present as a local extension to C in non-
                    113:  *    POSIX systems. fstat () can distinguish between real files and file-like
                    114:  *    objects such as named pipes.
                    115:  *  - It is usually possible to fstat () objects that cannot be accessed,
                    116:  *    which means extra complexity such as getuid () if restrictive
                    117:  *    permissions are set up. Testing for unusual objects such as pipes may
                    118:  *    reduce portability to systems which don't possess such objects.
                    119:  *
                    120:  * Additional considerations when using a system that may involve a large
                    121:  * directory tree is whether to walk the tree with chdir () rather than
                    122:  * building large pathnames which require expensive rescanning by the
                    123:  * operating system, and so forth.
                    124:  *
                    125:  * This file uses fopen () and simple macro-substitution in pathnames, since
                    126:  * performance is a lesser concern than portability. As for permissions, the
                    127:  * user of this program should be highly priveleged in order to be able to
                    128:  * specify the contents of the kernel code; the user has to be able to read
                    129:  * the files we scan for in order to compile or link them during the actual
                    130:  * kernel build phase.
                    131:  */
                    132: 
                    133: #define PATH_MACRO     1
                    134: 
                    135: struct macro_spec {
                    136:        char            ms_macrochar;   /* character after '%' sign */
                    137:        CONST char    * ms_envname;     /* environment variable to override */
                    138:        CONST char    * ms_default;
                    139:        CONST char    * ms_value;               /* Actual value */
                    140: } macros [] = {
                    141:        { 'p' },                                /* built at run-time */
                    142:        { 'P', "CONFPATH", DOS_OR_UNIX (".", ".") },
                    143:        { 'T', "OBJPATH", DOS_OR_UNIX ("obj", "obj") },
                    144:        { 'o', "OBJEXT", DOS_OR_UNIX ("obj", "o") },
                    145:        { 'O', "LIBEXT", DOS_OR_UNIX ("lib", "a") },
                    146:        { 'c', "CEXT", DOS_OR_UNIX ("c", "c") },
                    147:        { 'C', "CPPEXT", DOS_OR_UNIX ("cpp", "cc") }
                    148: };
                    149: 
                    150: 
                    151: /*
                    152:  * Since all the entries in the "make_spec" are strings which we want to treat
                    153:  * in a uniform way, we arrange things as an array rather than a structure.
                    154:  */
                    155: 
                    156: enum {
                    157:        TEST_FILE,
                    158:        LINK_ENTRY,
                    159:        COMPILE_RULES,
                    160:        CLEAN_ENTRY,
                    161:        BEFORE_ENTRY,
                    162:        BEFORE_RULES,
                    163:        AFTER_ENTRY,
                    164:        AFTER_RULES,
                    165: 
                    166:        MAKE_MAX
                    167: };
                    168: 
                    169: 
                    170: /*
                    171:  * Special entries for use to mean "*exactly* the same as" some previously
                    172:  * generated entry. This save generating multiple copies of the macroexpanded
                    173:  * text to save memory.
                    174:  */
                    175: 
                    176: CONST char SAME_AS [MAKE_MAX] [1];
                    177: 
                    178: 
                    179: /*
                    180:  * Structure of make specifications. The macroexpanded versions are kept
                    181:  * around so that the strings can be emitted in appropriate phases of the
                    182:  * make-file generation.
                    183:  */
                    184: 
                    185: typedef        struct make_spec        make_t;
                    186: 
                    187: struct make_spec {
                    188:        CONST char    * m_specs [MAKE_MAX];
                    189:        make_t        * m_next;
                    190: };
                    191: 
                    192: make_t config_commands [] = {
                    193:        { { "%P/%p/Driver.%O", "%P/%p/Driver.%O ", NULL, NULL,
                    194:                NULL, NULL, NULL, NULL } },
                    195:        { { "%P/%p/Driver.%o", "%P/%p/Driver.%o ", NULL, NULL,
                    196:                NULL, NULL, NULL, NULL } },
                    197:        { { "%P/%p/Space.%c", "%T/%p.%o ",
                    198:                "%2: %1\n\t$(CC) $(CFLAGS) -I%P/%p -I. -o"
                    199:                        DOS_OR_UNIX ("", " ") "%2 -c %1\n\n",
                    200:                SAME_AS [LINK_ENTRY],
                    201:                NULL, NULL, NULL, NULL } },
                    202:        { { "%P/%p/Space.%C", "%T/%p.%o",
                    203:                "%2: %1\n\t$(CC) $(CFLAGS) -I%P/%p -o"
                    204:                        DOS_OR_UNIX ("", " ") "%2 -c %1\n\n",
                    205:                SAME_AS [LINK_ENTRY],
                    206:                NULL, NULL, NULL, NULL } }
                    207: };
                    208: 
                    209: make_t stub_commands [] = {
                    210:        { { "%P/%p/Stub.%o", "%P/%p/Stub.%o ", NULL, NULL,
                    211:                NULL, NULL, NULL, NULL } }
                    212: };
                    213: 
                    214: make_t pre_commands [] = {
                    215:        { { "%P/%p/before", NULL, NULL, NULL,
                    216:                "%P/%p/before ", NULL,
                    217:                NULL, NULL } }
                    218: };
                    219: 
                    220: make_t post_commands [] = {
                    221:        { { "%P/%p/after", NULL, NULL, NULL,
                    222:                NULL, NULL,
                    223:                "%P/%p/after ", NULL } }
                    224: };
                    225: 
                    226: #define        ARRAY_LENGTH(a)         (sizeof (a) / sizeof (* a))
                    227: 
                    228: 
                    229: /*
                    230:  * Check the named file for existence.
                    231:  */
                    232: 
                    233: #if    USE_PROTO
                    234: LOCAL int file_exists (CONST char * name)
                    235: #else
                    236: LOCAL int
                    237: file_exists ARGS ((name))
                    238: CONST char    *        name;
                    239: #endif
                    240: {
                    241:        FILE          * temp;
                    242: 
                    243:        if ((temp = fopen (name, "r")) == NULL)
                    244:                return 0;
                    245: 
                    246:        fclose (temp);
                    247:        return 1;
                    248: }
                    249: 
                    250: 
                    251: /*
                    252:  * Set up macros, checking environment variables and selecting defaults. This
                    253:  * function also sets up the 'prefix' macro variable.
                    254:  */
                    255: 
                    256: #if    USE_PROTO
                    257: LOCAL void (init_macros) (CONST char * prefix)
                    258: #else
                    259: LOCAL void
                    260: init_macros ARGS ((prefix))
                    261: CONST char    *        prefix;
                    262: #endif
                    263: {
                    264:        int             i;
                    265: 
                    266:        for (i = 0 ; i < ARRAY_LENGTH (macros) ; i ++) {
                    267: 
                    268:                if (macros [i].ms_envname == NULL)
                    269:                        macros [i].ms_value = prefix;
                    270: 
                    271:                if (macros [i].ms_value == NULL &&
                    272:                    (macros [i].ms_value =
                    273:                                getenv (macros [i].ms_envname)) == NULL)
                    274:                        macros [i].ms_value = macros [i].ms_default;
                    275:        }
                    276: }
                    277: 
                    278: 
                    279: /*
                    280:  * Macroexpand a single entry in a make specification.
                    281:  */
                    282: 
                    283: #if    USE_PROTO
                    284: LOCAL void (expand_line) (make_t * spec, make_t * target, build_t * heap,
                    285:                          int line)
                    286: #else
                    287: LOCAL void
                    288: expand_line ARGS ((spec, target, heap, line))
                    289: make_t       * spec;
                    290: make_t       * target;
                    291: build_t              * heap;
                    292: int            line;
                    293: #endif
                    294: {
                    295:        int             i;
                    296:        CONST char    * scan;
                    297: 
                    298:        /*
                    299:         * Check to see if the spec wants to be identical to a
                    300:         * previous entry.
                    301:         */
                    302: 
                    303:        scan = spec->m_specs [line];
                    304: 
                    305:        for (i = 0 ; i < line ; i ++)
                    306:                if (scan == SAME_AS [i]) {
                    307: 
                    308:                        target->m_specs [line] = target->m_specs [i];
                    309:                        return;
                    310:                }
                    311: 
                    312:        /*
                    313:         * We will need to build a new entry in the heap.
                    314:         */
                    315: 
                    316:        if ((i = build_begin (heap, 0, NULL)) != 0)
                    317:                throw_error ("Cannot begin make line, error %s",
                    318:                             build_error (i));
                    319: 
                    320:        for (;;) {
                    321:                CONST char    * start;
                    322:                char            ch;
                    323: 
                    324:                /*
                    325:                 * Begin by moving any constant stuff to the output.
                    326:                 */
                    327: 
                    328:                start = scan;
                    329: 
                    330:                while ((ch = * scan ++) != 0 && ch != '%')
                    331:                        ;       /* DO NOTHING */
                    332: 
                    333:                /*
                    334:                 * If we have hit the last character in the source string,
                    335:                 * add that into the section we copy to the output, since it
                    336:                 * make manipulating the strings simpler :-).
                    337:                 */
                    338: 
                    339:                if ((i = scan - start - (ch != 0)) > 0 &&
                    340:                    (i == build_add (heap, i, start)) != 0)
                    341:                        throw_error ("Unable to add to make macro, error %s",
                    342:                                     build_error (i));
                    343: 
                    344:                if (ch == 0) {
                    345:                        /*
                    346:                         * End the macro generation and record the start
                    347:                         * address of the generated text in the output record.
                    348:                         */
                    349: 
                    350:                        if ((target->m_specs [line] =
                    351:                                        build_end (heap, NULL)) == NULL)
                    352:                                throw_error ("Error ending make macro");
                    353:                        return;
                    354:                }
                    355: 
                    356: 
                    357:                /*
                    358:                 * To get here we must have hit a '%'-sign, so deal with it.
                    359:                 *
                    360:                 * Our test for the numeric macros assumes that the digits
                    361:                 * have consecutive character codes in the executuion
                    362:                 * environment.
                    363:                 */
                    364: 
                    365:                ch = * scan ++;
                    366: 
                    367:                if (ch == 0)
                    368:                        throw_error ("Bad macro specification in expand_line ()");
                    369:                else if (ch > '0' && ch - '1' < line)
                    370:                        start = target->m_specs [ch - '1'];
                    371:                else if (ch == '%')
                    372:                        start = "%";
                    373:                else {
                    374:                        /*
                    375:                         * Scan the macro table for a match on 'ch'.
                    376:                         */
                    377: 
                    378:                        start = NULL;
                    379: 
                    380:                        for (i = 0 ; i < ARRAY_LENGTH (macros) ; i ++)
                    381:                                if (macros [i].ms_macrochar == ch) {
                    382: 
                    383:                                        start = macros [i].ms_value;
                    384:                                        break;
                    385:                                }
                    386:                }
                    387: 
                    388: 
                    389:                /*
                    390:                 * Copy the macro expansion to the destination.
                    391:                 */
                    392: 
                    393:                if (start != NULL &&
                    394:                    (i = build_add (heap, strlen (start), start)) != 0)
                    395:                        throw_error ("Unable to add to make macro, error %s",
                    396:                                     build_error (i));
                    397:        }
                    398: }
                    399: 
                    400: 
                    401: /*
                    402:  * Macroexpand the make specification template, building the target macros in
                    403:  * a build heap. If the file named by the first line does not exist, then
                    404:  * discard that name and return, otherwise expand the rest of the macros and
                    405:  * return an indication that the caller should record this entry.
                    406:  */
                    407: 
                    408: #if    USE_PROTO
                    409: LOCAL int (expand_spec) (make_t * spec, make_t * target, build_t * heap)
                    410: #else
                    411: LOCAL int
                    412: expand_spec ARGS ((spec, target, heap))
                    413: make_t       * spec;
                    414: make_t       * target;
                    415: build_t              * heap;
                    416: #endif
                    417: {
                    418:        int             i;
                    419: 
                    420:        expand_line (spec, target, heap, TEST_FILE);
                    421: 
                    422:        if (! file_exists (target->m_specs [TEST_FILE])) {
                    423: 
                    424:                if (build_release (heap, target->m_specs [TEST_FILE]) != 0)
                    425:                        throw_error ("Cannot release macro memory in expand_spec ()");
                    426: 
                    427:                return 0;
                    428:        }
                    429: 
                    430:        for (i = TEST_FILE + 1 ; i < MAKE_MAX ; i ++) {
                    431: 
                    432:                if (spec->m_specs [i] == NULL) {
                    433: 
                    434:                        target->m_specs [i] = NULL;
                    435:                        continue;
                    436:                }
                    437: 
                    438:                expand_line (spec, target, heap, i);
                    439:        }
                    440: 
                    441:        return 1;
                    442: }
                    443: 
                    444: 
                    445: /*
                    446:  * This function builds up part of a makefile specification.
                    447:  */
                    448: 
                    449: #if    USE_PROTO
                    450: LOCAL make_t * (make_make) (build_t * heap, CONST char * prefix,
                    451:                            make_t * specs, int nspecs, make_t * makelist)
                    452: #else
                    453: LOCAL make_t *
                    454: make_make ARGS ((heap, prefix, specs, nspecs, makelist))
                    455: build_t              * heap;
                    456: CONST char    *        prefix;
                    457: make_t       * specs;
                    458: int            nspecs;
                    459: make_t       * makelist;
                    460: #endif
                    461: {
                    462:        int             i;
                    463:        make_t          temp;
                    464:        make_t        * scan;
                    465: 
                    466:        init_macros (prefix);
                    467: 
                    468:        for (i = 0 ; i < nspecs ; i ++) {
                    469:                /*
                    470:                 * Expand the specifications, and then test to see if the file
                    471:                 * named by the first part of the expanded specification
                    472:                 * exists.
                    473:                 */
                    474: 
                    475:                if (expand_spec (specs + i, & temp, heap)) {
                    476:                        /*
                    477:                         * Add the specification to the list of items to be
                    478:                         * included in the makefile. We do a quick scan for
                    479:                         * duplicate file-name strings, just for paranoia.
                    480:                         */
                    481: 
                    482:                        for (scan = makelist ; scan != NULL ;
                    483:                             scan = scan->m_next) {
                    484: 
                    485:                                if (strcmp (scan->m_specs [TEST_FILE],
                    486:                                            temp.m_specs [TEST_FILE]) == 0)
                    487:                                        continue;
                    488:                        }
                    489: 
                    490:                        if ((scan = (make_t *)
                    491:                                        build_malloc (heap,
                    492:                                                      sizeof (temp))) == NULL)
                    493:                                throw_error ("Out of memory in make_make ()");
                    494: 
                    495:                        * scan = temp;
                    496:                        scan->m_next = makelist;
                    497:                        makelist = scan;
                    498:                }
                    499:        }
                    500: 
                    501:        return makelist;
                    502: }
                    503: 
                    504: 
                    505: /*
                    506:  * Structure for emulating local functions in C with the function following.
                    507:  */
                    508: 
                    509: struct make {
                    510:        build_t       * _heap;
                    511:        make_t        * _spec;
                    512: };
                    513: 
                    514: #if    USE_PROTO
                    515: LOCAL void _write_makefile (struct make * make, mdev_t * mdevp)
                    516: #else
                    517: LOCAL void
                    518: _write_makefile (make, mdevp)
                    519: struct make   *        make;
                    520: mdev_t       * mdevp;
                    521: #endif
                    522: {
                    523:        CONST char *    data = mdevp->md_devname->s_data;
                    524: 
                    525:        make->_spec = mdevp->md_configure == MD_ENABLED ?
                    526:                make_make (make->_heap, data, config_commands,
                    527:                           ARRAY_LENGTH (config_commands),
                    528:                           make_make (make->_heap, data, post_commands,
                    529:                                      ARRAY_LENGTH (post_commands),
                    530:                                      make_make (make->_heap, data,
                    531:                                                 pre_commands,
                    532:                                                 ARRAY_LENGTH (pre_commands),
                    533:                                                 make->_spec))) :
                    534:                make_make (make->_heap, data, stub_commands,
                    535:                           ARRAY_LENGTH (stub_commands), make->_spec);
                    536: }
                    537: 
                    538: 
                    539: /*
                    540:  * Iterate over all the mdevice entries and run over either the 'config' or
                    541:  * 'stub' make-file specifications.
                    542:  */
                    543: 
                    544: #if    USE_PROTO
                    545: LOCAL void (write_makefile) (FILE * out, input_t * example, build_t * heap)
                    546: #else
                    547: LOCAL void
                    548: write_makefile ARGS ((out, example, heap))
                    549: FILE         * out;
                    550: input_t              * example;
                    551: build_t              * heap;
                    552: #endif
                    553: {
                    554:        int             ch;
                    555:        struct make     make;
                    556:        char            pathbuf [80];
                    557: 
                    558:        make._heap = heap;
                    559:        make._spec = NULL;
                    560: 
                    561:        init_macros (NULL);
                    562:        
                    563:        if (getcwd (pathbuf, sizeof (pathbuf)) == NULL)
                    564:                throw_error ("write_makefile () : cannot save current directory");
                    565: 
                    566:        if (chdir (macros [PATH_MACRO].ms_value) != 0)
                    567:                throw_error ("write_makefile () : cannot change directory, "
                    568:                             "OS says %s", strerror (errno));
                    569:             
                    570:        for_all_mdevices ((miter_t) _write_makefile, & make);
                    571: 
                    572:        chdir (pathbuf);
                    573: 
                    574:        /*
                    575:         * Actually generate the output from a template file, expanding '%'-
                    576:         * commands in the template into lists of strings as generated above.
                    577:         */
                    578: 
                    579:        while ((ch = read_char (example)) != READ_EOF) {
                    580:                make_t        * scan;
                    581: 
                    582:                switch (ch) {
                    583: 
                    584:                case '%':
                    585:                        switch (ch = read_char (example)) {
                    586: 
                    587:                        case '%':
                    588:                                fputc (ch, out);
                    589:                                break;
                    590: 
                    591:                        case 'T':
                    592:                                ch = TEST_FILE;
                    593:                                goto write_list;
                    594: 
                    595:                        case 'l':
                    596:                                ch = LINK_ENTRY;
                    597:                                goto write_list;
                    598: 
                    599:                        case 'C':
                    600:                                ch = COMPILE_RULES;
                    601:                                goto write_list;
                    602: 
                    603:                        case 'r':
                    604:                                ch = CLEAN_ENTRY;
                    605:                                goto write_list;
                    606: 
                    607:                        case 'b':
                    608:                                ch = BEFORE_ENTRY;
                    609:                                goto write_list;
                    610: 
                    611:                        case 'B':
                    612:                                ch = BEFORE_RULES;
                    613:                                goto write_list;
                    614: 
                    615:                        case 'a':
                    616:                                ch = AFTER_ENTRY;
                    617:                                goto write_list;
                    618: 
                    619:                        case 'A':
                    620:                                ch = AFTER_RULES;
                    621: write_list:
                    622:                                for (scan = make._spec ; scan != NULL ;
                    623:                                     scan = scan->m_next) {
                    624: 
                    625:                                        if (scan->m_specs [ch] == NULL)
                    626:                                                continue;
                    627: 
                    628:                                        fputs (scan->m_specs [ch], out);
                    629:                                }
                    630: 
                    631:                                break;
                    632: 
                    633:                        default:
                    634:                                read_error (example);
                    635:                                throw_error ("Bad %%-entry in template file");
                    636:                        }
                    637:                        break;
                    638: 
                    639:                default:
                    640:                        fputc (ch, out);
                    641:                        break;
                    642:                }
                    643:        }
                    644: }
                    645: 
                    646: 
                    647: /*
                    648:  * Write out a detailed set of compile/link commands which will set up a new
                    649:  * kernel. It searches the appropriate directories where driver object files
                    650:  * are expected to be installed and determines what files should be linked
                    651:  * based on the presence of files with appropriate names.
                    652:  */
                    653: 
                    654: #if    USE_PROTO
                    655: int (write_link) (CONST char * outname, CONST char * inname)
                    656: #else
                    657: int
                    658: write_link ARGS ((outname, inname))
                    659: CONST char    *        outname;
                    660: CONST char    *        inname;
                    661: #endif
                    662: {
                    663:        time_t          gentime;
                    664:        char            timebuf [70];
                    665:        char            pathbuf [80];
                    666:        FILE * VOLATILE out;
                    667:        FILE *          in;
                    668:        input_t * VOLATILE example;
                    669:        ehand_t         err;
                    670:        build_t       * heap;
                    671:        int             closein = 1;
                    672:        int             closeout = 1;
                    673: 
                    674:        if ((heap = builder_alloc (256, 1)) == NULL)
                    675:                throw_error ("Unable to allocate temporary heap in write_link ()");
                    676: 
                    677:        if (inname == NULL) {
                    678:                in = stdin;
                    679:                inname = "template";
                    680:                closein = 0;
                    681:        } else if ((in = fopen (inname, "r")) == NULL)
                    682:                throw_error ("Unable to open template file in write_link ()");
                    683: 
                    684:        if (outname == NULL) {
                    685:                out = stdout;
                    686:                closeout = 0;
                    687:        } else if ((out = fopen (outname, "w")) == NULL)
                    688:                throw_error ("Unable to open output file for writing in write_link ()");
                    689: 
                    690:        if ((example = make_filter (in, inname, closein, '#',
                    691:                                    out, closeout)) == NULL)
                    692:                throw_error ("Out of memory in write_link ()");
                    693: 
                    694:        if (PUSH_HANDLER (err) == 0) {
                    695:                time (& gentime);
                    696: 
                    697:                fprintf (out, "# Kernel makefile\n");
                    698:                fprintf (out, "# This makefile was automatically generated."
                    699:                              " Do not hand-modify\n");
                    700: 
                    701: #ifdef __COHERENT__
                    702:                strncpy (timebuf, asctime (localtime (& gentime)),
                    703:                         sizeof (timebuf) - 1);
                    704:                timebuf [sizeof (timebuf) - 1] = 0;
                    705: #else
                    706:                strftime (timebuf, sizeof (timebuf) - 1, "%x %X %Z",
                    707:                          localtime (& gentime));
                    708: #endif
                    709: 
                    710:                fprintf (out, "# Generated at %s\n", timebuf);
                    711: 
                    712:                write_makefile (out, example, heap);
                    713: 
                    714:                read_close (example);
                    715:                builder_free (heap);
                    716: 
                    717:        } else {
                    718:                read_close (example);
                    719:                builder_free (heap);
                    720: 
                    721:                CHAIN_ERROR (err);
                    722:        }
                    723: 
                    724:        POP_HANDLER (err);
                    725:        return 0;
                    726: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.