krx51300.c

来自「answer of the c programming language sec」· C语言 代码 · 共 808 行 · 第 1/2 页

C
808
字号

void version(void)
{
    puts( "tail - output the last part of files" );
    puts( "Version 1.0" );
    puts( "Written by Gregory Pietsch" );
}

/* allocate memory, die on error */
void *xmalloc(size_t n)
{
    void *p = malloc(n);

    if (p == NULL) {
        fprintf(stderr, "%s: out of memory\n", program_name);
        exit(EXIT_FAILURE);
    }
    return p;
}

/* reallocate memory, die on error */
void *xrealloc(void *p, size_t n)
{
    void *s;

    if (n == 0) {
        if (p != NULL)
            free(p);
        return NULL;
    }
    if (p == NULL)
        return xmalloc(n);
    s = realloc(p, n);
    if (s == NULL) {
        fprintf(stderr, "%s: out of memory\n", program_name);
        exit(EXIT_FAILURE);
    }
    return s;
}

/* get string duplicate */
char *xstrdup(char *s)
{
    char *p = xmalloc(strlen(s) + 1);

    strcpy(p, s);
    return p;
}

/* queue stuff - get fresh queue */
LINE_QUEUE_T *lq_create(void)
{
    LINE_QUEUE_T *lq = xmalloc(sizeof LINE_QUEUE_T);

    lq->first = NULL;
    lq->last = NULL;
    lq->num_elements = 0;
    return lq;
}

/* put an item onto the queue */
void lq_enq(LINE_QUEUE_T * lq, char *s)
{
    LINE_QUEUE_EL_T *lq_el = xmalloc(sizeof LINE_QUEUE_EL_T);

    lq_el->s = xstrdup(s);
    lq_el->next = NULL;
    if (lq->first == NULL && lq->last == NULL) {
        /* first element */
        lq->first = lq->last = lq_el;
        lq->num_elements = 1;
    }
    else {
        /* tack onto end */
        lq->last->next = lq_el;
        lq->last = lq_el;
        lq->num_elements++;
    }
}

/* take an item off the queue */
char *lq_deq(LINE_QUEUE_T * lq)
{
    char *s;
    LINE_QUEUE_EL_T *lq_el;

    if (lq->first == NULL)
        return NULL;
    lq_el = lq->first;
    s = lq_el->s;
    if (lq->first == lq->last)
        lq->first = lq->last = NULL;
    else
        lq->first = lq->first->next;
    free(lq_el);
    lq->num_elements--;
    return s;
}

/* output number lines -- this function is tough because I can only
 * use fseek() to rewind a text stream (See ISO C 7.9.9.2 if you don't
 * believe me).
 */
void tail_lines(FILE * f)
{
    char buffer[TAIL_BUFFER_SIZE];
    size_t num_read;
    int last_is_nl = 0;
    unsigned long num_skipped = 0;
    int c;
    LINE_QUEUE_T *lq = NULL;
    char *s;
    size_t s_size = 0;
    size_t s_allocked = 0;
    char *p;

    if (flag_skip) {
        /* skip a bunch of lines, output everything else */
        while ((c = getc(f)) != EOF && num_skipped < number) {
            if (c == '\n')
                num_skipped++;
        }
        while ((num_read = fread(buffer, 1, TAIL_BUFFER_SIZE, f)) != 0)
{
            fwrite(buffer, 1, num_read, stdout);
            last_is_nl = (buffer[num_read - 1] == '\n');
        }
        if (!last_is_nl)
            fputc('\n', stdout);
    }
    else {
        lq = lq_create();
        s = xmalloc(TAIL_STRING_BUFFER_SIZE);
        s_allocked = TAIL_STRING_BUFFER_SIZE;
        while ((c = getc(f)) != EOF) {
            /* add to s, if not at eof or end of line */
            if (c != '\n') {
                if (s_size == s_allocked - 1) {
                    s_allocked += TAIL_STRING_BUFFER_SIZE;
                    s = xrealloc(s, s_allocked);
                }
                s[s_size++] = c;
            }
            else {
                /* enqueue s, possibly dequeueing if we don't need a
line */
                s[s_size] = '\0';
                lq_enq(lq, s);
                if (lq->num_elements > number)
                    free(lq_deq(lq));
                s_size = 0;
            }
        }
        while (lq->num_elements != 0) {
            /* print out strings */
            p = lq_deq(lq);
            puts(p);
            free(p);
        }
        free(s);
        free(lq);
    }
}

/* output number characters, or skip over number characters */
void tail_chars(FILE * f)
{
    char buffer[TAIL_BUFFER_SIZE];
    size_t num_read;
    int last_is_nl = 0;
    long lnum = number;

    if (flag_skip)
        fseek(f, lnum, SEEK_SET);
    else
        fseek(f, -lnum, SEEK_END);
    while ((num_read = fread(buffer, 1, TAIL_BUFFER_SIZE, f)) != 0) {
        fwrite(buffer, 1, num_read, stdout);
        last_is_nl = (buffer[num_read - 1] == '\n');
    }
    if (!last_is_nl)
        fputc('\n', stdout);
}

void parse_args(int argc, char **argv)
{
    int opt;
    char *p;
    int flag_found_number = 0;
    int verbosity_changed = 0;

    do {
        switch ((opt = getopt_long(argc, argv, shortopts, longopts, NULL))) {
        case 'c':               /* print bytes */
            if (flag_found_number) {
                fprintf(stderr, "%s: invalid arguments\s", program_name);
                abort();
            }
            flag_bytes = 1;
            p = optarg;
            if (*p == '+') {
                flag_skip = 1;
                p++;
            }
            for (number = 0;
                 isdigit(*p);
                 number = number * 10 + (*p++ - '0'));
            switch (*p) {
            case 'b':           /* 512-byte blocks */
                number *= 512;
                break;
            case 'k':           /* kilobyte blocks */
                number *= 1024;
                break;
            case 'm':           /* megabyte blocks */
                number *= 1048576;
                break;
            default:
                break;
            }
            flag_found_number = 1;
            break;
        case 'l':
        case 'n':               /* lines */
            if (flag_found_number) {
                fprintf(stderr, "%s: invalid arguments\s", program_name);
                abort();
            }
            flag_bytes = 0;
            p = optarg;
            if (*p == '+') {
                flag_skip = 1;
                p++;
            }
            number = strtoul(p, NULL, 10);
            flag_found_number = 1;
            break;
        case 'q':               /* quiet */
            if (verbosity_changed) {
                fprintf(stderr, "%s: invalid arguments\s", program_name);
                abort();
            }
            verbosity_changed = 1;
            flag_verbosity = NEVER;
            break;
        case 'v':               /* verbose */
            if (verbosity_changed) {
                fprintf(stderr, "%s: invalid arguments\s", program_name);
                abort();
            }
            verbosity_changed = 1;
            flag_verbosity = ALWAYS;
            break;
        case '?':               /* invalid option */
            fprintf(stderr, "For help, type:\n\t%s --help\n", program_name);
            exit(EXIT_FAILURE);
        case 1:
        case 0:
            if (show_help || show_version) {
                if (show_help)
                    help();
                if (show_version)
                    version();
                exit(EXIT_SUCCESS);
            }
            break;
        default:
            break;
        }
    } while (opt != EOF);
    if (flag_found_number == 0 || number == 0) {
        /* didn't find anything, so set default */
        flag_bytes = 0;
        number = 10;
    }
}

int main(int argc, char **argv)
{
    int i;
    int j;
    unsigned long ul;
    char **new_argv = xmalloc((argc + 1) * (sizeof(char *)));
    char *allocked_argvs = xmalloc(argc + 1);
    char *p;
    char *s;
    char *t;
    FILE *f;
    int flag_plus = 0;

    memset(allocked_argvs, 0, argc + 1);
    new_argv[0] = program_name = argv[0];
    /* deal with silly old-format arguments */
    for (i = 1, j = 1; i < argc; i++) {
        p = argv[i];
        flag_plus = 0;
        /* handle options first */
        if (*p == '-' || *p == '+') {
            if (isdigit(p[1]) || p[1] == '+' || *p == '+') {
                /* rearrange p */
                s = xmalloc(strlen(p) + 3);
                t = s;
                *t++ = '-';
                if (*p == '-')
                    p++;
                ul = 0;
                if (*p == '+') {
                    flag_plus = 1;
                    p++;
                }
                while (isdigit(*p)) {
                    ul = ul * 10 + (*p - '0');
                    p++;
                }
                if (strchr(p, 'q') != NULL)
                    *t++ = 'q';
                if (strchr(p, 'v') != NULL)
                    *t++ = 'v';
                if (strpbrk(p, "cbkm") != NULL)
                    *t++ = 'c';
                if (strchr(p, 'l') != NULL)
                    *t++ = 'l';
                if (strchr(p, 'n') != NULL || t[-1] == '-')
                    *t++ = 'n';
                if (flag_plus)
                    *t++ = '+';
                sprintf(t, "%lu", ul);
                t += strlen(t);
                if (strchr(p, 'b') != NULL)
                    *t++ = 'b';
                if (strchr(p, 'k') != NULL)
                    *t++ = 'k';
                if (strchr(p, 'm') != NULL)
                    *t++ = 'm';
                *t = '\0';
                new_argv[j] = s;
                allocked_argvs[j++] = 1;
            }
            else
                new_argv[j++] = argv[i];
        }
    }
    for (i = 1; i < argc; i++) {
        /* handle file names */
        p = argv[i];
        if (*p != '-')
            new_argv[j++] = p;
    }
    new_argv[argc] = NULL;
    parse_args(argc, new_argv);
    if (optind == argc
        || (optind == argc - 1 && strcmp(argv[optind], "-") == 0)) {
        /* no more argv-elements, tail stdin */
        if (flag_verbosity == ALWAYS)
            puts("==> standard input <==");
        flag_bytes ? tail_chars(stdin) : tail_lines(stdin);
    }
    else if (optind == argc - 1) {
        /* one file */
        f = fopen(new_argv[optind], flag_bytes ? "rb" : "r");
        if (f == NULL) {
            fprintf(stderr, "%s: Can't open file %s\n",
                    program_name, new_argv[optind]);
            abort();
        }
        if (flag_verbosity == ALWAYS)
            printf("==> %s <==\n", new_argv[optind]);
        flag_bytes ? tail_chars(f) : tail_lines(f);
        fclose(f);
    }
    else {
        /* multiple files */
        for (i = optind; i < argc; i++) {
            if (strcmp(new_argv[i], "-") == 0) {
                f = stdin;
                if (flag_verbosity != NEVER)
                    puts("==> standard input <==");
            }
            else {
                f = fopen(new_argv[i], flag_bytes ? "rb" : "r");
                if (f == NULL) {
                    fprintf(stderr, "%s: can't open %s\n",
                            argv[0], argv[i]);
                    abort();
                }
                if (flag_verbosity != NEVER)
                    printf("==> %s <==\n", new_argv[i]);
            }
            flag_bytes ? tail_chars(f) : tail_lines(f);
            if (f != stdin)
                fclose(f);
        }
    }
    /* free all we can */
    for (i = 1; i <= argc; i++)
        if (allocked_argvs[i])
            free(new_argv[i]);
    free(allocked_argvs);
    return EXIT_SUCCESS;
}

/* END OF FILE tail.c */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?