cmdutils.c 19 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1 2 3 4
/*
 * Various utilities for command line tools
 * Copyright (c) 2000-2003 Fabrice Bellard
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
Fabrice Bellard's avatar
Fabrice Bellard committed
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Fabrice Bellard's avatar
Fabrice Bellard committed
20
 */
21

22 23 24
#include <string.h>
#include <stdlib.h>
#include <errno.h>
25
#include <math.h>
26

27 28 29 30
/* Include only the enabled headers since some compilers (namely, Sun
   Studio) will not omit unused inline functions and create undefined
   references to libraries that are not being built. */

31
#include "config.h"
32 33 34
#include "libavformat/avformat.h"
#include "libavfilter/avfilter.h"
#include "libavdevice/avdevice.h"
35
#include "libswscale/swscale.h"
36
#include "libpostproc/postprocess.h"
37
#include "libavutil/avstring.h"
38
#include "libavcodec/opt.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
39
#include "cmdutils.h"
40
#include "version.h"
Ramiro Polla's avatar
Ramiro Polla committed
41
#if CONFIG_NETWORK
42
#include "libavformat/network.h"
Ramiro Polla's avatar
Ramiro Polla committed
43
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
44

45 46
#undef exit

47 48
const char **opt_names;
static int opt_name_count;
49
AVCodecContext *avcodec_opts[CODEC_TYPE_NB];
50 51
AVFormatContext *avformat_opts;
struct SwsContext *sws_opts;
52

53 54
const int this_year = 2009;

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
double parse_number_or_die(const char *context, const char *numstr, int type, double min, double max)
{
    char *tail;
    const char *error;
    double d = strtod(numstr, &tail);
    if (*tail)
        error= "Expected number for %s but found: %s\n";
    else if (d < min || d > max)
        error= "The value for %s was %s which is not within %f - %f\n";
    else if(type == OPT_INT64 && (int64_t)d != d)
        error= "Expected int64 for %s but found %s\n";
    else
        return d;
    fprintf(stderr, error, context, numstr, min, max);
    exit(1);
}

72 73 74 75 76 77 78 79 80 81 82
int64_t parse_time_or_die(const char *context, const char *timestr, int is_duration)
{
    int64_t us = parse_date(timestr, is_duration);
    if (us == INT64_MIN) {
        fprintf(stderr, "Invalid %s specification for %s: %s\n",
                is_duration ? "duration" : "date", context, timestr);
        exit(1);
    }
    return us;
}

83
void show_help_options(const OptionDef *options, const char *msg, int mask, int value)
Fabrice Bellard's avatar
Fabrice Bellard committed
84 85
{
    const OptionDef *po;
86
    int first;
Fabrice Bellard's avatar
Fabrice Bellard committed
87

88 89 90 91 92 93 94 95
    first = 1;
    for(po = options; po->name != NULL; po++) {
        char buf[64];
        if ((po->flags & mask) == value) {
            if (first) {
                printf("%s", msg);
                first = 0;
            }
96
            av_strlcpy(buf, po->name, sizeof(buf));
97
            if (po->flags & HAS_ARG) {
98 99
                av_strlcat(buf, " ", sizeof(buf));
                av_strlcat(buf, po->argname, sizeof(buf));
Fabrice Bellard's avatar
Fabrice Bellard committed
100
            }
101
            printf("-%-17s  %s\n", buf, po->help);
Fabrice Bellard's avatar
Fabrice Bellard committed
102 103 104 105
        }
    }
}

Måns Rullgård's avatar
Måns Rullgård committed
106
static const OptionDef* find_option(const OptionDef *po, const char *name){
107 108 109 110 111 112 113 114
    while (po->name != NULL) {
        if (!strcmp(name, po->name))
            break;
        po++;
    }
    return po;
}

115 116
void parse_options(int argc, char **argv, const OptionDef *options,
                   void (* parse_arg_function)(const char*))
Fabrice Bellard's avatar
Fabrice Bellard committed
117 118
{
    const char *opt, *arg;
119
    int optindex, handleoptions=1;
Fabrice Bellard's avatar
Fabrice Bellard committed
120 121 122 123 124 125
    const OptionDef *po;

    /* parse options */
    optindex = 1;
    while (optindex < argc) {
        opt = argv[optindex++];
126

127
        if (handleoptions && opt[0] == '-' && opt[1] != '\0') {
128
            int bool_val = 1;
Stefano Sabatini's avatar
Stefano Sabatini committed
129 130 131 132
            if (opt[1] == '-' && opt[2] == '\0') {
                handleoptions = 0;
                continue;
            }
133
            po= find_option(options, opt + 1);
134 135 136 137 138 139 140
            if (!po->name && opt[1] == 'n' && opt[2] == 'o') {
                /* handle 'no' bool option */
                po = find_option(options, opt + 3);
                if (!(po->name && (po->flags & OPT_BOOL)))
                    goto unknown_opt;
                bool_val = 0;
            }
141 142
            if (!po->name)
                po= find_option(options, "default");
Fabrice Bellard's avatar
Fabrice Bellard committed
143
            if (!po->name) {
144
unknown_opt:
Fabrice Bellard's avatar
Fabrice Bellard committed
145 146 147 148 149 150 151 152 153 154 155 156 157
                fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], opt);
                exit(1);
            }
            arg = NULL;
            if (po->flags & HAS_ARG) {
                arg = argv[optindex++];
                if (!arg) {
                    fprintf(stderr, "%s: missing argument for option '%s'\n", argv[0], opt);
                    exit(1);
                }
            }
            if (po->flags & OPT_STRING) {
                char *str;
158
                str = av_strdup(arg);
Fabrice Bellard's avatar
Fabrice Bellard committed
159 160
                *po->u.str_arg = str;
            } else if (po->flags & OPT_BOOL) {
161
                *po->u.int_arg = bool_val;
Michael Niedermayer's avatar
Michael Niedermayer committed
162
            } else if (po->flags & OPT_INT) {
163
                *po->u.int_arg = parse_number_or_die(opt+1, arg, OPT_INT64, INT_MIN, INT_MAX);
164
            } else if (po->flags & OPT_INT64) {
165
                *po->u.int64_arg = parse_number_or_die(opt+1, arg, OPT_INT64, INT64_MIN, INT64_MAX);
Michael Niedermayer's avatar
Michael Niedermayer committed
166
            } else if (po->flags & OPT_FLOAT) {
167
                *po->u.float_arg = parse_number_or_die(opt+1, arg, OPT_FLOAT, -1.0/0.0, 1.0/0.0);
168 169 170
            } else if (po->flags & OPT_FUNC2) {
                if(po->u.func2_arg(opt+1, arg)<0)
                    goto unknown_opt;
Fabrice Bellard's avatar
Fabrice Bellard committed
171
            } else {
172
                po->u.func_arg(arg);
Fabrice Bellard's avatar
Fabrice Bellard committed
173
            }
Michael Niedermayer's avatar
Michael Niedermayer committed
174 175
            if(po->flags & OPT_EXIT)
                exit(0);
Fabrice Bellard's avatar
Fabrice Bellard committed
176
        } else {
177 178
            if (parse_arg_function)
                parse_arg_function(opt);
Fabrice Bellard's avatar
Fabrice Bellard committed
179 180 181 182
        }
    }
}

183 184
int opt_default(const char *opt, const char *arg){
    int type;
185
    int ret= 0;
186 187 188
    const AVOption *o= NULL;
    int opt_types[]={AV_OPT_FLAG_VIDEO_PARAM, AV_OPT_FLAG_AUDIO_PARAM, 0, AV_OPT_FLAG_SUBTITLE_PARAM, 0};

189
    for(type=0; type<CODEC_TYPE_NB && ret>= 0; type++){
190
        const AVOption *o2 = av_find_opt(avcodec_opts[0], opt, NULL, opt_types[type], opt_types[type]);
191
        if(o2)
192
            ret = av_set_string3(avcodec_opts[type], opt, arg, 1, &o);
193 194
    }
    if(!o)
195
        ret = av_set_string3(avformat_opts, opt, arg, 1, &o);
196
    if(!o)
197
        ret = av_set_string3(sws_opts, opt, arg, 1, &o);
198 199
    if(!o){
        if(opt[0] == 'a')
200
            ret = av_set_string3(avcodec_opts[CODEC_TYPE_AUDIO], opt+1, arg, 1, &o);
201
        else if(opt[0] == 'v')
202
            ret = av_set_string3(avcodec_opts[CODEC_TYPE_VIDEO], opt+1, arg, 1, &o);
203
        else if(opt[0] == 's')
204
            ret = av_set_string3(avcodec_opts[CODEC_TYPE_SUBTITLE], opt+1, arg, 1, &o);
205 206 207 208
    }
    if (o && ret < 0) {
        fprintf(stderr, "Invalid value '%s' for option '%s'\n", arg, opt);
        exit(1);
209 210 211 212
    }
    if(!o)
        return -1;

213
//    av_log(NULL, AV_LOG_ERROR, "%s:%s: %f 0x%0X\n", opt, arg, av_get_double(avcodec_opts, opt, NULL), (int)av_get_int(avcodec_opts, opt, NULL));
214

215
    //FIXME we should always use avcodec_opts, ... for storing options so there will not be any need to keep track of what i set over this
216 217 218
    opt_names= av_realloc(opt_names, sizeof(void*)*(opt_name_count+1));
    opt_names[opt_name_count++]= o->name;

219
    if(avcodec_opts[0]->debug || avformat_opts->debug)
220 221 222 223
        av_log_set_level(AV_LOG_DEBUG);
    return 0;
}

224 225
int opt_loglevel(const char *opt, const char *arg)
{
226
    const struct { const char *name; int level; } log_levels[] = {
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
        { "quiet"  , AV_LOG_QUIET   },
        { "panic"  , AV_LOG_PANIC   },
        { "fatal"  , AV_LOG_FATAL   },
        { "error"  , AV_LOG_ERROR   },
        { "warning", AV_LOG_WARNING },
        { "info"   , AV_LOG_INFO    },
        { "verbose", AV_LOG_VERBOSE },
        { "debug"  , AV_LOG_DEBUG   },
    };
    char *tail;
    int level;
    int i;

    for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) {
        if (!strcmp(log_levels[i].name, arg)) {
            av_log_set_level(log_levels[i].level);
            return 0;
        }
    }

    level = strtol(arg, &tail, 10);
    if (*tail) {
        fprintf(stderr, "Invalid loglevel \"%s\". "
                        "Possible levels are numbers or:\n", arg);
        for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++)
            fprintf(stderr, "\"%s\"\n", log_levels[i].name);
        exit(1);
    }
    av_log_set_level(level);
    return 0;
}

259 260 261 262 263 264 265 266 267
void set_context_opts(void *ctx, void *opts_ctx, int flags)
{
    int i;
    for(i=0; i<opt_name_count; i++){
        char buf[256];
        const AVOption *opt;
        const char *str= av_get_string(opts_ctx, opt_names[i], &opt, buf, sizeof(buf));
        /* if an option with name opt_names[i] is present in opts_ctx then str is non-NULL */
        if(str && ((opt->flags & flags) == flags))
268
            av_set_string3(ctx, opt_names[i], str, 1, NULL);
269 270 271
    }
}

Fabrice Bellard's avatar
Fabrice Bellard committed
272 273 274 275 276 277 278
void print_error(const char *filename, int err)
{
    switch(err) {
    case AVERROR_NUMEXPECTED:
        fprintf(stderr, "%s: Incorrect image filename syntax.\n"
                "Use '%%d' to specify the image number:\n"
                "  for img1.jpg, img2.jpg, ..., use 'img%%d.jpg';\n"
279
                "  for img001.jpg, img002.jpg, ..., use 'img%%03d.jpg'.\n",
Fabrice Bellard's avatar
Fabrice Bellard committed
280 281 282 283 284 285 286 287
                filename);
        break;
    case AVERROR_INVALIDDATA:
        fprintf(stderr, "%s: Error while parsing header\n", filename);
        break;
    case AVERROR_NOFMT:
        fprintf(stderr, "%s: Unknown format\n", filename);
        break;
288
    case AVERROR(EIO):
289
        fprintf(stderr, "%s: I/O error occurred\n"
290 291
                "Usually that means that input file is truncated and/or corrupted.\n",
                filename);
292
        break;
293
    case AVERROR(ENOMEM):
294
        fprintf(stderr, "%s: memory allocation error occurred\n", filename);
295
        break;
296
    case AVERROR(ENOENT):
297 298
        fprintf(stderr, "%s: no such file or directory\n", filename);
        break;
299
#if CONFIG_NETWORK
300 301 302
    case AVERROR(FF_NETERROR(EPROTONOSUPPORT)):
        fprintf(stderr, "%s: Unsupported network protocol\n", filename);
        break;
303
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
304 305 306 307 308
    default:
        fprintf(stderr, "%s: Error while opening file\n", filename);
        break;
    }
}
309

310 311 312 313 314 315
#define PRINT_LIB_VERSION(outstream,libname,LIBNAME,indent) \
    version= libname##_version(); \
    fprintf(outstream, "%slib%-10s %2d.%2d.%2d / %2d.%2d.%2d\n", indent? "  " : "", #libname, \
            LIB##LIBNAME##_VERSION_MAJOR, LIB##LIBNAME##_VERSION_MINOR, LIB##LIBNAME##_VERSION_MICRO, \
            version >> 16, version >> 8 & 0xff, version & 0xff);

316
static void print_all_lib_versions(FILE* outstream, int indent)
317 318
{
    unsigned int version;
319 320
    PRINT_LIB_VERSION(outstream, avutil,   AVUTIL,   indent);
    PRINT_LIB_VERSION(outstream, avcodec,  AVCODEC,  indent);
321 322
    PRINT_LIB_VERSION(outstream, avformat, AVFORMAT, indent);
    PRINT_LIB_VERSION(outstream, avdevice, AVDEVICE, indent);
323
#if CONFIG_AVFILTER
324 325
    PRINT_LIB_VERSION(outstream, avfilter, AVFILTER, indent);
#endif
326
    PRINT_LIB_VERSION(outstream, swscale,  SWSCALE,  indent);
327
#if CONFIG_POSTPROC
328 329
    PRINT_LIB_VERSION(outstream, postproc, POSTPROC, indent);
#endif
330 331
}

332
void show_banner(void)
333
{
334 335
    fprintf(stderr, "%s version " FFMPEG_VERSION ", Copyright (c) %d-%d Fabrice Bellard, et al.\n",
            program_name, program_birth_year, this_year);
336 337
    fprintf(stderr, "  built on %s %s with %s %s\n",
            __DATE__, __TIME__, CC_TYPE, CC_VERSION);
338 339
    fprintf(stderr, "  configuration: " FFMPEG_CONFIGURATION "\n");
    print_all_lib_versions(stderr, 1);
340 341
}

342
void show_version(void) {
343
    printf("%s " FFMPEG_VERSION "\n", program_name);
344
    print_all_lib_versions(stdout, 0);
345 346
}

347 348
void show_license(void)
{
349
    printf(
350
#if CONFIG_NONFREE
351 352 353
    "This version of %s has nonfree parts compiled in.\n"
    "Therefore it is not legally redistributable.\n",
    program_name
354 355 356 357 358 359 360 361 362 363 364 365 366 367
#elif CONFIG_GPLV3
    "%s is free software; you can redistribute it and/or modify\n"
    "it under the terms of the GNU General Public License as published by\n"
    "the Free Software Foundation; either version 3 of the License, or\n"
    "(at your option) any later version.\n"
    "\n"
    "%s is distributed in the hope that it will be useful,\n"
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
    "GNU General Public License for more details.\n"
    "\n"
    "You should have received a copy of the GNU General Public License\n"
    "along with %s.  If not, see <http://www.gnu.org/licenses/>.\n",
    program_name, program_name, program_name
368
#elif CONFIG_GPL
369
    "%s is free software; you can redistribute it and/or modify\n"
370 371 372 373
    "it under the terms of the GNU General Public License as published by\n"
    "the Free Software Foundation; either version 2 of the License, or\n"
    "(at your option) any later version.\n"
    "\n"
374
    "%s is distributed in the hope that it will be useful,\n"
375 376 377 378 379
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
    "GNU General Public License for more details.\n"
    "\n"
    "You should have received a copy of the GNU General Public License\n"
380 381 382
    "along with %s; if not, write to the Free Software\n"
    "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n",
    program_name, program_name, program_name
383 384 385 386 387 388 389 390 391 392 393 394 395 396
#elif CONFIG_LGPLV3
    "%s is free software; you can redistribute it and/or modify\n"
    "it under the terms of the GNU Lesser General Public License as published by\n"
    "the Free Software Foundation; either version 3 of the License, or\n"
    "(at your option) any later version.\n"
    "\n"
    "%s is distributed in the hope that it will be useful,\n"
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
    "GNU Lesser General Public License for more details.\n"
    "\n"
    "You should have received a copy of the GNU Lesser General Public License\n"
    "along with %s.  If not, see <http://www.gnu.org/licenses/>.\n",
    program_name, program_name, program_name
397
#else
398
    "%s is free software; you can redistribute it and/or\n"
399 400 401 402
    "modify it under the terms of the GNU Lesser General Public\n"
    "License as published by the Free Software Foundation; either\n"
    "version 2.1 of the License, or (at your option) any later version.\n"
    "\n"
403
    "%s is distributed in the hope that it will be useful,\n"
404 405 406 407 408
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
    "Lesser General Public License for more details.\n"
    "\n"
    "You should have received a copy of the GNU Lesser General Public\n"
409 410 411
    "License along with %s; if not, write to the Free Software\n"
    "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n",
    program_name, program_name, program_name
412
#endif
413
    );
414
}
415 416 417 418 419 420 421 422 423 424

void show_formats(void)
{
    AVInputFormat *ifmt=NULL;
    AVOutputFormat *ofmt=NULL;
    URLProtocol *up=NULL;
    AVCodec *p=NULL, *p2;
    AVBitStreamFilter *bsf=NULL;
    const char *last_name;

425 426 427 428 429
    printf(
        "File formats:\n"
        " D. = Demuxing supported\n"
        " .E = Muxing supported\n"
        " --\n");
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
    last_name= "000";
    for(;;){
        int decode=0;
        int encode=0;
        const char *name=NULL;
        const char *long_name=NULL;

        while((ofmt= av_oformat_next(ofmt))) {
            if((name == NULL || strcmp(ofmt->name, name)<0) &&
                strcmp(ofmt->name, last_name)>0){
                name= ofmt->name;
                long_name= ofmt->long_name;
                encode=1;
            }
        }
        while((ifmt= av_iformat_next(ifmt))) {
            if((name == NULL || strcmp(ifmt->name, name)<0) &&
                strcmp(ifmt->name, last_name)>0){
                name= ifmt->name;
                long_name= ifmt->long_name;
                encode=0;
            }
            if(name && strcmp(ifmt->name, name)==0)
                decode=1;
        }
        if(name==NULL)
            break;
        last_name= name;

        printf(
            " %s%s %-15s %s\n",
            decode ? "D":" ",
            encode ? "E":" ",
            name,
            long_name ? long_name:" ");
    }
    printf("\n");

468 469 470 471 472 473 474 475 476 477 478
    printf(
        "Codecs:\n"
        " D..... = Decoding supported\n"
        " .E.... = Encoding supported\n"
        " ..V... = Video codec\n"
        " ..A... = Audio codec\n"
        " ..S... = Subtitle codec\n"
        " ...S.. = Supports draw_horiz_band\n"
        " ....D. = Supports direct rendering method 1\n"
        " .....T = Supports weird frame truncation\n"
        " ------\n");
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
    last_name= "000";
    for(;;){
        int decode=0;
        int encode=0;
        int cap=0;
        const char *type_str;

        p2=NULL;
        while((p= av_codec_next(p))) {
            if((p2==NULL || strcmp(p->name, p2->name)<0) &&
                strcmp(p->name, last_name)>0){
                p2= p;
                decode= encode= cap=0;
            }
            if(p2 && strcmp(p->name, p2->name)==0){
                if(p->decode) decode=1;
                if(p->encode) encode=1;
                cap |= p->capabilities;
            }
        }
        if(p2==NULL)
            break;
        last_name= p2->name;

        switch(p2->type) {
        case CODEC_TYPE_VIDEO:
            type_str = "V";
            break;
        case CODEC_TYPE_AUDIO:
            type_str = "A";
            break;
        case CODEC_TYPE_SUBTITLE:
            type_str = "S";
            break;
        default:
            type_str = "?";
            break;
        }
        printf(
            " %s%s%s%s%s%s %-15s %s",
            decode ? "D": (/*p2->decoder ? "d":*/" "),
            encode ? "E":" ",
            type_str,
            cap & CODEC_CAP_DRAW_HORIZ_BAND ? "S":" ",
            cap & CODEC_CAP_DR1 ? "D":" ",
            cap & CODEC_CAP_TRUNCATED ? "T":" ",
            p2->name,
            p2->long_name ? p2->long_name : "");
       /* if(p2->decoder && decode==0)
            printf(" use %s for decoding", p2->decoder->name);*/
        printf("\n");
    }
    printf("\n");

    printf("Bitstream filters:\n");
    while((bsf = av_bitstream_filter_next(bsf)))
        printf(" %s", bsf->name);
    printf("\n");

    printf("Supported file protocols:\n");
    while((up = av_protocol_next(up)))
        printf(" %s:", up->name);
    printf("\n");

    printf("Frame size, frame rate abbreviations:\n ntsc pal qntsc qpal sntsc spal film ntsc-film sqcif qcif cif 4cif\n");
    printf("\n");
    printf(
"Note, the names of encoders and decoders do not always match, so there are\n"
"several cases where the above table shows encoder only or decoder only entries\n"
"even though both encoding and decoding are supported. For example, the h263\n"
"decoder corresponds to the h263 and h263p encoders, for file formats it is even\n"
"worse.\n");
}
552 553 554 555 556 557 558 559 560 561 562

int read_yesno(void)
{
    int c = getchar();
    int yesno = (toupper(c) == 'Y');

    while (c != '\n' && c != EOF)
        c = getchar();

    return yesno;
}