Annotation of coherent/b/STREAMS/conf/bin/src/mdev.c, revision 1.1

1.1     ! root        1: /*
        !             2:  *-IMPORT:
        !             3:  *     <sys/compat.h>
        !             4:  *             CONST
        !             5:  *             LOCAL
        !             6:  *             USE_PROTO
        !             7:  *             ARGS ()
        !             8:  *     <stdlib.h>
        !             9:  *             NULL
        !            10:  *             free ()
        !            11:  *             malloc ()
        !            12:  *     <string.h>
        !            13:  *             strchr ()
        !            14:  *     "ehand.h"
        !            15:  *             ehand_t
        !            16:  *             CHAIN_ERROR ()
        !            17:  *             POP_HANDLER ()
        !            18:  *             PUSH_HANDLER ()
        !            19:  *             throw_error ()
        !            20:  *     "symbol.h"
        !            21:  *             LEX_WILD
        !            22:  *             RANGE
        !            23:  *             SIGNED
        !            24:  *             SYM_EOF
        !            25:  *             UNSIGNED
        !            26:  *             read_dev_file ()
        !            27:  *             read_number ()
        !            28:  *             read_symbol ()
        !            29:  */
        !            30: 
        !            31: #include <sys/compat.h>
        !            32: #include <stdlib.h>
        !            33: #include <string.h>
        !            34: 
        !            35: #include "ehand.h"
        !            36: #include "symbol.h"
        !            37: #include "read.h"
        !            38: #include "lex.h"
        !            39: #include "input.h"
        !            40: 
        !            41: #include "mdev.h"
        !            42: 
        !            43: 
        !            44: LOCAL mdev_t  *        _mdevices;
        !            45: 
        !            46: 
        !            47: /*
        !            48:  * Find a device by symbol.
        !            49:  */
        !            50: 
        !            51: #if    USE_PROTO
        !            52: mdev_t * (find_mdev) (symbol_t * sym)
        !            53: #else
        !            54: mdev_t *
        !            55: find_mdev ARGS ((sym))
        !            56: symbol_t      *        sym;
        !            57: #endif
        !            58: {
        !            59:        mdev_t        * scan;
        !            60: 
        !            61:        for (scan = _mdevices ; scan != NULL ; scan = scan->md_next) {
        !            62: 
        !            63:                if (scan->md_devname == sym)
        !            64:                        return scan;
        !            65:        }
        !            66: 
        !            67:        return NULL;
        !            68: }
        !            69: 
        !            70: 
        !            71: /*
        !            72:  * Write a single number or a range of device major numbers.
        !            73:  */
        !            74: 
        !            75: #if    USE_PROTO
        !            76: LOCAL int write_range (input_t * input, maj_t major [2])
        !            77: #else
        !            78: LOCAL int
        !            79: write_range (input, major)
        !            80: input_t              * input;
        !            81: maj_t          major [2];
        !            82: #endif
        !            83: {
        !            84:        if (major [0] == major [1])
        !            85:                return (* input->in_filter) (input, "%d\t", major [0]);
        !            86: 
        !            87:        return (* input->in_filter) (input, "%d-%d\t", major [0], major [1]);
        !            88: }
        !            89: 
        !            90: 
        !            91: /*
        !            92:  * Regenerate an 'mdevice' line from the stored record.
        !            93:  */
        !            94: 
        !            95: #define        HYPHEN(x)       ((x) == NULL ? (unsigned char *) "-" : (x))
        !            96: 
        !            97: #if    USE_PROTO
        !            98: void (write_mdevice) (mdev_t * mdevp, input_t * input)
        !            99: #else
        !           100: void
        !           101: write_mdevice ARGS ((mdevp, input))
        !           102: mdev_t       * mdevp;
        !           103: input_t              * input;
        !           104: #endif
        !           105: {
        !           106:        if ((* input->in_filter) (input, "%s<1>%s<2>%s<3>%s<4>",
        !           107:                                  mdevp->md_devname->s_data,
        !           108:                                  HYPHEN (mdevp->md_functions->s_data),
        !           109:                                  HYPHEN (mdevp->md_flags->s_data),
        !           110:                                  mdevp->md_prefix->s_data) < 0 ||
        !           111:            write_range (input, mdevp->md_blk_maj) < 0 ||
        !           112:            write_range (input, mdevp->md_chr_maj) < 0 ||
        !           113:            (* input->in_filter) (input, "%d<7>%d<8>%d<9>%d\n",
        !           114:                                  mdevp->md_minor_min, mdevp->md_minor_max,
        !           115:                                  mdevp->md_dma_chan, mdevp->md_cpu_id) < 0) {
        !           116: 
        !           117:                throw_error ("Output error");
        !           118:        }
        !           119: }
        !           120: 
        !           121: 
        !           122: /*
        !           123:  * Read lines from an "mdevice" file.
        !           124:  *
        !           125:  * This code is really messy. My apologies.
        !           126:  */
        !           127: 
        !           128: #if    USE_PROTO
        !           129: LOCAL mdev_t * (read_mdevice) (input_t * input, lex_t * lexp, int * end_char)
        !           130: #else
        !           131: LOCAL mdev_t *
        !           132: read_mdevice ARGS ((input, lexp, end_char))
        !           133: input_t              * input;
        !           134: lex_t         *        lexp;
        !           135: int          * end_char;
        !           136: #endif
        !           137: {
        !           138:        VOLATILE int    ch = '\n';
        !           139:        mdev_t * VOLATILE mdevp;
        !           140:        ehand_t         err;
        !           141:        lex_t           functions = { NULL, NULL, "-", MDEV_FUNCS, LEX_WILD };
        !           142:        lex_t           flags = { NULL, NULL, "-", MDEV_FLAGS, LEX_WILD };
        !           143: 
        !           144:        functions.l_prev = lexp;
        !           145:        flags.l_prev = lexp;
        !           146: 
        !           147:        if ((mdevp = (mdev_t *) malloc (sizeof (* mdevp))) == NULL)
        !           148:                throw_error ("out of memory in read_mdevice ()");
        !           149: 
        !           150:        if (PUSH_HANDLER (err) == 0) {
        !           151:                /*
        !           152:                 * If the first thing on the line works out to be an EOF,
        !           153:                 * then bail out without an error.
        !           154:                 */
        !           155: 
        !           156:                ch = read_symbol (input, lexp, & mdevp->md_devname);
        !           157: 
        !           158:                if (mdevp->md_devname == NULL) {
        !           159:                        /*
        !           160:                         * We allow an EOF at the beginning of a line and we
        !           161:                         * also allow a blank line.
        !           162:                         */
        !           163: 
        !           164:                        free (mdevp);
        !           165:                        mdevp = NULL;
        !           166:                        goto at_eof;
        !           167:                }
        !           168:                check_not_eol (ch);
        !           169: 
        !           170:                if (mdevp->md_devname->s_size > MAX_DEVNAME)
        !           171:                        throw_error ("device name must be <= %d characters",
        !           172:                                     MAX_DEVNAME);
        !           173: 
        !           174:                /*
        !           175:                 * We read the functions and characteristics field as symbols,
        !           176:                 * even though they are really strings, since it makes no
        !           177:                 * difference to the result.
        !           178:                 */
        !           179: 
        !           180:                ch = read_symbol (input, & functions, & mdevp->md_functions);
        !           181:                if (mdevp->md_functions == NULL && ch != '-')
        !           182:                        throw_error ("Unable to read functions");
        !           183:                check_not_eol (ch);
        !           184: 
        !           185:                ch = read_symbol (input, & flags, & mdevp->md_flags);
        !           186:                if (mdevp->md_flags == NULL && ch != '-')
        !           187:                        throw_error ("Unable to read flags");
        !           188:                check_not_eol (ch);
        !           189: 
        !           190:                if ((mdev_flag (mdevp, MDEV_BLOCK) ||
        !           191:                     mdev_flag (mdevp, MDEV_CHAR) ||
        !           192:                     mdev_flag (mdevp, MDEV_STREAM)) &&
        !           193:                    ! mdev_flag (mdevp, MDEV_DDI_DDK)) {
        !           194: 
        !           195:                        throw_error ("devices must be DDI/DDK compliant");
        !           196:                }
        !           197: 
        !           198: 
        !           199:                /*
        !           200:                 * We don't check for a unique device prefix, since there may
        !           201:                 * be a legitimate reason to configure the same prefix twice.
        !           202:                 *
        !           203:                 * If the user installs multiple devices with the same prefix,
        !           204:                 * the linker should catch it. Of course, a registration
        !           205:                 * system might help. We only enforce the size limit for
        !           206:                 * drivers... other kernel facilities can user longer names.
        !           207:                 */
        !           208: 
        !           209:                ch = read_symbol (input, lexp, & mdevp->md_prefix);
        !           210:                check_not_eol (ch);
        !           211: 
        !           212:                if ((mdev_flag (mdevp, MDEV_BLOCK) ||
        !           213:                     mdev_flag (mdevp, MDEV_CHAR) ||
        !           214:                     mdev_flag (mdevp, MDEV_STREAM)) &&
        !           215:                    mdevp->md_prefix->s_size > MAX_PREFIX)
        !           216:                        throw_error ("device prefix must be <= %d characters",
        !           217:                                     MAX_PREFIX);
        !           218: 
        !           219: 
        !           220:                ch = read_uints (input, lexp, mdevp->md_blk_maj, RANGE);
        !           221:                check_not_eol (ch);
        !           222: 
        !           223:                if (mdev_flag (mdevp, MDEV_BLOCK)) {
        !           224: 
        !           225:                        if (mdevp->md_blk_maj [0] > mdevp->md_blk_maj [1])
        !           226:                                throw_error ("lower range bound higher than upper bound");
        !           227: 
        !           228:                        if (mdevp->md_blk_maj [0] < MAJOR_RESERVED)
        !           229:                                throw_error ("major devices up to %d reserved",
        !           230:                                             MAJOR_RESERVED - 1);
        !           231: 
        !           232:                } else if (mdev_flag (mdevp, MDEV_COHERENT)) {
        !           233: 
        !           234:                        if (mdevp->md_blk_maj [0] != mdevp->md_blk_maj [1])
        !           235:                                throw_error ("Coherent devices occupy a single major number");
        !           236: 
        !           237:                        if (mdevp->md_blk_maj [0] >= MAJOR_RESERVED)
        !           238:                                throw_error ("Coherent devices only in range 0-%d",
        !           239:                                             MAJOR_RESERVED - 1);
        !           240:                } else
        !           241:                        mdevp->md_blk_maj [0] = mdevp->md_blk_maj [1] = 0;
        !           242: 
        !           243: 
        !           244:                ch = read_uints (input, lexp, mdevp->md_chr_maj, RANGE);
        !           245:                check_not_eol (ch);
        !           246: 
        !           247:                if (mdev_flag (mdevp, MDEV_CHAR)) {
        !           248: 
        !           249:                        if (mdevp->md_chr_maj [0] > mdevp->md_chr_maj [1])
        !           250:                                throw_error ("lower range bound higher that upper bound");
        !           251: 
        !           252:                        if (mdevp->md_chr_maj [0] < MAJOR_RESERVED)
        !           253:                                throw_error ("major devices 0-%d reserved",
        !           254:                                             MAJOR_RESERVED - 1);
        !           255:                } else if (mdev_flag (mdevp, MDEV_COHERENT)) {
        !           256: 
        !           257:                        if (mdevp->md_chr_maj [0] != mdevp->md_blk_maj [0] ||
        !           258:                            mdevp->md_blk_maj [0] != mdevp->md_chr_maj [0])
        !           259:                                throw_error ("Coherent drivers must have same "
        !           260:                                             "block and character numbers");
        !           261:                } else
        !           262:                        mdevp->md_chr_maj [0] = mdevp->md_chr_maj [1] = 0;
        !           263: 
        !           264:                ch = read_uints (input, lexp, & mdevp->md_minor_min,
        !           265:                                 NO_RANGE);
        !           266:                check_not_eol (ch);
        !           267: 
        !           268:                ch = read_uints (input, lexp, & mdevp->md_minor_max,
        !           269:                                 NO_RANGE);
        !           270:                check_not_eol (ch);
        !           271: 
        !           272:                if (mdevp->md_minor_min > mdevp->md_minor_max)
        !           273:                        throw_error ("minor minimum higher than maximum");
        !           274: 
        !           275:                ch = read_ints (input, lexp, & mdevp->md_dma_chan, NO_RANGE);
        !           276: 
        !           277:                if (ch != '\n' && ch != SYM_EOF) {
        !           278:                        /*
        !           279:                         * The "cpu_id" field is optional.
        !           280:                         */
        !           281: 
        !           282:                        ch = read_ints (input, lexp, & mdevp->md_cpu_id,
        !           283:                                        NO_RANGE);
        !           284:                } else
        !           285:                        mdevp->md_cpu_id = -1;
        !           286: 
        !           287:                ch = expect_eol (input, lexp, ch);
        !           288: 
        !           289: 
        !           290:                /*
        !           291:                 * Having passed all the reasonableness checks, we link the
        !           292:                 * new entry into the chain.
        !           293:                 */
        !           294: 
        !           295:                mdevp->md_sdevices = NULL;
        !           296:                mdevp->md_interrupt = 0;
        !           297: 
        !           298:                mdevp->md_configure = MD_INSTALLABLE;
        !           299:        } else {
        !           300: 
        !           301:                free (mdevp);
        !           302:                CHAIN_ERROR (err);
        !           303:        }
        !           304: 
        !           305: at_eof:
        !           306:        POP_HANDLER (err);
        !           307: 
        !           308:        * end_char = ch;
        !           309:        return mdevp;
        !           310: }
        !           311: 
        !           312: 
        !           313: /*
        !           314:  * This function is passed as a parameter to read_dev_string () to read an
        !           315:  * 'mtune' entry (usually a program argument) and hook it into a global list.
        !           316:  */
        !           317: 
        !           318: #if    USE_PROTO
        !           319: LOCAL int _read_mdev_string (input_t * input, lex_t * lexp,
        !           320:                              mdev_t ** mdlistp)
        !           321: #else
        !           322: LOCAL int
        !           323: _read_mdev_string (input, lexp, mdlistp)
        !           324: input_t              * input;
        !           325: lex_t        * lexp;
        !           326: mdev_t      ** mdlistp;
        !           327: #endif
        !           328: {
        !           329:        mdev_t        * mdevp;
        !           330:        int             ch;
        !           331: 
        !           332:        if ((mdevp = read_mdevice (input, lexp, & ch)) != NULL) {
        !           333:                mdevp->md_next = * mdlistp;
        !           334:                * mdlistp = mdevp;
        !           335:        }
        !           336: 
        !           337:        return ch;
        !           338: }
        !           339: 
        !           340: 
        !           341: /*
        !           342:  * Common code from _read_mdevice_file () to link an entry into the global
        !           343:  * 'mdevice' chain.
        !           344:  */
        !           345: 
        !           346: #if    USE_PROTO
        !           347: LOCAL void (link_mdevice) (mdev_t * mdevp, input_t * input)
        !           348: #else
        !           349: LOCAL void
        !           350: link_mdevice ARGS ((mdevp, input))
        !           351: mdev_t       * mdevp;
        !           352: input_t              * input;
        !           353: #endif
        !           354: {
        !           355:        if (find_mdev (mdevp->md_devname) != NULL)
        !           356:                throw_error ("device name must be unique");
        !           357: 
        !           358:        mdevp->md_next = _mdevices;
        !           359:        _mdevices = mdevp;
        !           360: 
        !           361:        write_mdevice (mdevp, input);
        !           362: }
        !           363: 
        !           364: 
        !           365: /*
        !           366:  * This function is passed as a pointer to read_dev_file () to read an
        !           367:  * 'mdevice' entry from the input and link it in to the global device list.
        !           368:  *
        !           369:  * The extra argument is the head of a list of 'mdevice' entries which are to
        !           370:  * replace/be added to the existing 'mdevice' entries.
        !           371:  */
        !           372: 
        !           373: #if    USE_PROTO
        !           374: LOCAL int _read_mdevice_file (input_t * input, lex_t * lexp, 
        !           375:                              mdev_t ** changes)
        !           376: #else
        !           377: LOCAL int
        !           378: _read_mdevice_file (input, lexp, changes)
        !           379: input_t              * input;
        !           380: lex_t        * lexp;
        !           381: mdev_t      ** changes;
        !           382: #endif
        !           383: {
        !           384:        mdev_t        * mdevp;
        !           385:        int             ch;
        !           386: 
        !           387:        if ((mdevp = read_mdevice (input, lexp, & ch)) == NULL) {
        !           388:                if (ch == READ_EOF) {
        !           389:                        /*
        !           390:                         * Blow the remaining changes out as new entries.
        !           391:                         */
        !           392: 
        !           393:                        while ((mdevp = * changes) != NULL) {
        !           394:                                * changes = mdevp->md_next;
        !           395:                                link_mdevice (mdevp, input);
        !           396:                        }
        !           397:                }
        !           398:                return ch;
        !           399:        }
        !           400: 
        !           401:        /*
        !           402:         * Link the newly-allocated mdevice entry into the global
        !           403:         * mdevice chain.
        !           404:         */
        !           405: 
        !           406:        if (changes) {
        !           407:                mdev_t       ** scan;
        !           408: 
        !           409:                for (scan = changes ; * scan != NULL ;
        !           410:                     scan = & (* scan)->md_next) {
        !           411: 
        !           412:                        if ((* scan)->md_devname == mdevp->md_devname) {
        !           413:                                /*
        !           414:                                 * Our current entry is being replaced by a
        !           415:                                 * new one; unlink the new entry from the
        !           416:                                 * change list and discard the old entry.
        !           417:                                 */
        !           418: 
        !           419:                                free (mdevp);
        !           420: 
        !           421:                                if (report_mode ())
        !           422:                                        return ch;
        !           423: 
        !           424:                                mdevp = * scan;
        !           425:                                * scan = mdevp->md_next;
        !           426:                                break;
        !           427:                        }
        !           428:                }
        !           429:        }
        !           430: 
        !           431:        link_mdevice (mdevp, input);
        !           432:        return ch;
        !           433: }
        !           434: 
        !           435: 
        !           436: /*
        !           437:  * Test a device for a function code; returns 1 if code is present, or 0 if
        !           438:  * code is not specified for device.
        !           439:  */
        !           440: 
        !           441: #if    USE_PROTO
        !           442: int (mdev_func) (mdev_t * mdevp, char func)
        !           443: #else
        !           444: int
        !           445: mdev_func ARGS ((mdevp, func))
        !           446: mdev_t       * mdevp;
        !           447: char           func;
        !           448: #endif
        !           449: {
        !           450:        if (mdevp->md_functions == NULL)
        !           451:                return 0;
        !           452:        return strchr (mdevp->md_functions->s_data, func) != NULL;
        !           453: }
        !           454: 
        !           455: 
        !           456: /*
        !           457:  * Test device characteristics; returns 1 if characteristic is specified for
        !           458:  * device, 0 if it is not.
        !           459:  */
        !           460: 
        !           461: #if    USE_PROTO
        !           462: int (mdev_flag) (mdev_t * mdevp, char flag)
        !           463: #else
        !           464: int
        !           465: mdev_flag ARGS ((mdevp, flag))
        !           466: mdev_t       * mdevp;
        !           467: char           flag;
        !           468: #endif
        !           469: {
        !           470:        if (mdevp->md_flags == NULL)
        !           471:                return 0;
        !           472:        return strchr (mdevp->md_flags->s_data, flag) != NULL;
        !           473: }
        !           474: 
        !           475: 
        !           476: /*
        !           477:  * Read in an "mtune" entry from a string and add it to a list.
        !           478:  */
        !           479: 
        !           480: #if    USE_PROTO
        !           481: void read_mdev_string (CONST char * string, VOID * extra)
        !           482: #else
        !           483: void
        !           484: read_mdev_string (string, extra)
        !           485: CONST char    *        string;
        !           486: VOID         * extra;
        !           487: #endif
        !           488: {
        !           489:        read_dev_string (string, (dev_func_p) _read_mdev_string, extra);
        !           490: }
        !           491: 
        !           492: 
        !           493: /*
        !           494:  * Suck in a complete 'mdevice' file.
        !           495:  */
        !           496: 
        !           497: #if    USE_PROTO
        !           498: void (read_mdev_file) (CONST char * inname, CONST char * outname, VOID * extra)
        !           499: #else
        !           500: void
        !           501: read_mdev_file ARGS ((inname, outname, extra))
        !           502: CONST char    *        inname;
        !           503: CONST char    *        outname;
        !           504: VOID         * extra;
        !           505: #endif
        !           506: {
        !           507:        read_dev_file (inname, outname, (dev_func_p) _read_mdevice_file,
        !           508:                       extra);
        !           509: }
        !           510: 
        !           511: 
        !           512: /*
        !           513:  * Iterate over all the mdevices in the system.
        !           514:  */
        !           515: 
        !           516: #if    USE_PROTO
        !           517: void (for_all_mdevices) (miter_t iter, VOID * extra)
        !           518: #else
        !           519: void
        !           520: for_all_mdevices ARGS ((iter, extra))
        !           521: miter_t                iter;
        !           522: VOID         * extra;
        !           523: #endif
        !           524: {
        !           525:        mdev_t        * temp;
        !           526: 
        !           527:        for (temp = _mdevices ; temp != NULL ; temp = temp->md_next)
        !           528:                (* iter) (extra, temp);
        !           529: }
        !           530: 
        !           531: 
        !           532: /*
        !           533:  * Generic insertion sort algorithm for "mdevice" entries based on a
        !           534:  * selection predicate and a comparison predicate.
        !           535:  *
        !           536:  * So that this can be a reasonably generic function, we pass it the internal
        !           537:  * offset of the "mdev_t *" member of the "mdevice" structure which will be
        !           538:  * used to link together the sorted entries.
        !           539:  *
        !           540:  * The return value is the length of the sorted list.
        !           541:  */
        !           542: 
        !           543: #define        LINK(mdevp,off)         (* (mdev_t **) ((char *) (mdevp) + off))
        !           544: 
        !           545: #if    USE_PROTO
        !           546: int (mdev_sort) (mdev_t ** mdlistp, mdev_t ** mdendp, msel_t selpred,
        !           547:                 mcmp_t cmppred, size_t ptroff)
        !           548: #else
        !           549: int
        !           550: mdev_sort ARGS ((mdlistp, mdendp, selpred, cmppred, ptroff))
        !           551: mdev_t       **        mdlistp;
        !           552: mdev_t      ** mdendp;
        !           553: msel_t         selpred;
        !           554: mcmp_t         cmppred;
        !           555: size_t         ptroff;
        !           556: #endif
        !           557: {
        !           558:        mdev_t        * scan;
        !           559:        mdev_t        * next;
        !           560:        int             count;
        !           561: 
        !           562:        if (mdlistp == NULL || ptroff > sizeof (mdev_t))
        !           563:                throw_error ("bogus parameters to mdev_sort ()");
        !           564: 
        !           565: 
        !           566:        /*
        !           567:         * We'll just insert each selected member of the total list of
        !           568:         * mdevices into the output list in order by running down the output
        !           569:         * list until we compare true.
        !           570:         *
        !           571:         * We fetch "scan" before initializing the output list in case we are
        !           572:         * sorting the master device list.
        !           573:         */
        !           574: 
        !           575:        * mdlistp = NULL;
        !           576:        if (mdendp != NULL)
        !           577:                * mdendp = NULL;
        !           578: 
        !           579:        for (count = 0, scan = _mdevices ; scan != NULL ; scan = next) {
        !           580:                mdev_t        * findpos;
        !           581:                mdev_t        * prev;
        !           582: 
        !           583:                /*
        !           584:                 * We get the "next" entry now in case we are sorting the
        !           585:                 * master list. We allow a "selpred" of NULL to select all
        !           586:                 * the entries.
        !           587:                 */
        !           588: 
        !           589:                next = scan->md_next;
        !           590: 
        !           591:                if (selpred != NULL && (* selpred) (scan) == 0)
        !           592:                        continue;
        !           593: 
        !           594: 
        !           595:                /*
        !           596:                 * Now attempt to find the right place for the new entry and
        !           597:                 * insert it there.
        !           598:                 */
        !           599: 
        !           600:                prev = NULL;
        !           601: 
        !           602:                for (findpos = * mdlistp ; findpos != NULL ;
        !           603:                     findpos = LINK ((prev = findpos), ptroff)) {
        !           604:                        /*
        !           605:                         * A "cmppred" that is NULL means that the order of
        !           606:                          * output entries is irrelevant.
        !           607:                         */
        !           608: 
        !           609:                        if (cmppred == NULL ||
        !           610:                            (* cmppred) (findpos, scan) == 0)
        !           611:                                break;
        !           612:                }
        !           613: 
        !           614:                if (prev == NULL)
        !           615:                        * mdlistp = scan;
        !           616:                else
        !           617:                        LINK (prev, ptroff) = scan;
        !           618: 
        !           619:                if ((LINK (scan, ptroff) = findpos) == NULL && mdendp != NULL)
        !           620:                        * mdendp = scan;
        !           621: 
        !           622:                count ++;
        !           623:        }
        !           624: 
        !           625:        return count;
        !           626: }

unix.superglobalmegacorp.com

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