~ubuntu-branches/ubuntu/utopic/coreutils/utopic-proposed

« back to all changes in this revision

Viewing changes to src/seq.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2012-11-28 03:03:42 UTC
  • mfrom: (8.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20121128030342-21zanj8354gas5gr
Tags: 8.20-3ubuntu1
* Resynchronise with Debian.  Remaining changes:
  - Make 'uname -i -p' return the real processor/hardware, instead of
    unknown.
  - Build-depend on gettext:any instead of on gettext, so that apt-get can
    properly resolve build-dependencies on the tool when cross-building.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* seq - print sequence of numbers to standard output.
2
 
   Copyright (C) 1994-2011 Free Software Foundation, Inc.
 
2
   Copyright (C) 1994-2012 Free Software Foundation, Inc.
3
3
 
4
4
   This program is free software: you can redistribute it and/or modify
5
5
   it under the terms of the GNU General Public License as published by
33
33
# define isfinite(x) ((x) * 0 == 0)
34
34
#endif
35
35
 
36
 
/* The official name of this program (e.g., no `g' prefix).  */
 
36
/* The official name of this program (e.g., no 'g' prefix).  */
37
37
#define PROGRAM_NAME "seq"
38
38
 
39
39
#define AUTHORS proper_name ("Ulrich Drepper")
62
62
usage (int status)
63
63
{
64
64
  if (status != EXIT_SUCCESS)
65
 
    fprintf (stderr, _("Try `%s --help' for more information.\n"),
66
 
             program_name);
 
65
    emit_try_help ();
67
66
  else
68
67
    {
69
68
      printf (_("\
89
88
INCREMENT is usually negative if FIRST is greater than LAST.\n\
90
89
"), stdout);
91
90
      fputs (_("\
92
 
FORMAT must be suitable for printing one argument of type `double';\n\
 
91
FORMAT must be suitable for printing one argument of type 'double';\n\
93
92
it defaults to %.PRECf if FIRST, INCREMENT, and LAST are all fixed point\n\
94
93
decimal numbers with maximum precision PREC, and to %g otherwise.\n\
95
94
"), stdout);
336
335
  return "%Lg";
337
336
}
338
337
 
 
338
/* The NUL-terminated string S0 of length S_LEN represents a valid
 
339
   non-negative decimal integer.  Adjust the string and length so
 
340
   that the pair describe the next-larger value.  */
 
341
static void
 
342
incr (char **s0, size_t *s_len)
 
343
{
 
344
  char *s = *s0;
 
345
  char *endp = s + *s_len - 1;
 
346
 
 
347
  do
 
348
    {
 
349
      if ((*endp)++ < '9')
 
350
        return;
 
351
      *endp-- = '0';
 
352
    }
 
353
  while (endp >= s);
 
354
  *--(*s0) = '1';
 
355
  ++*s_len;
 
356
}
 
357
 
 
358
/* Compare A and B (each a NUL-terminated digit string), with lengths
 
359
   given by A_LEN and B_LEN.  Return +1 if A < B, -1 if B < A, else 0.  */
 
360
static int
 
361
cmp (char const *a, size_t a_len, char const *b, size_t b_len)
 
362
{
 
363
  if (a_len < b_len)
 
364
    return -1;
 
365
  if (b_len < a_len)
 
366
    return 1;
 
367
  return (strcmp (a, b));
 
368
}
 
369
 
 
370
/* Trim leading 0's from S, but if S is all 0's, leave one.
 
371
   Return a pointer to the trimmed string.  */
 
372
static char const * _GL_ATTRIBUTE_PURE
 
373
trim_leading_zeros (char const *s)
 
374
{
 
375
  char const *p = s;
 
376
  while (*s == '0')
 
377
    ++s;
 
378
 
 
379
  /* If there were only 0's, back up, to leave one.  */
 
380
  if (!*s && s != p)
 
381
    --s;
 
382
  return s;
 
383
}
 
384
 
 
385
/* Print all whole numbers from A to B, inclusive -- to stdout, each
 
386
   followed by a newline.  If B < A, return false and print nothing.
 
387
   Otherwise, return true.  */
 
388
static bool
 
389
seq_fast (char const *a, char const *b)
 
390
{
 
391
  /* Skip past any leading 0's.  Without this, our naive cmp
 
392
     function would declare 000 to be larger than 99.  */
 
393
  a = trim_leading_zeros (a);
 
394
  b = trim_leading_zeros (b);
 
395
 
 
396
  size_t p_len = strlen (a);
 
397
  size_t q_len = strlen (b);
 
398
  size_t n = MAX (p_len, q_len);
 
399
  char *p0 = xmalloc (n + 1);
 
400
  char *p = memcpy (p0 + n - p_len, a, p_len + 1);
 
401
  char *q0 = xmalloc (n + 1);
 
402
  char *q = memcpy (q0 + n - q_len, b, q_len + 1);
 
403
 
 
404
  bool ok = cmp (p, p_len, q, q_len) <= 0;
 
405
  if (ok)
 
406
    {
 
407
      /* Buffer at least this many output lines per fwrite call.
 
408
         This gives a speed-up of more than 2x over the unbuffered code
 
409
         when printing the first 10^9 integers.  */
 
410
      enum {N = 40};
 
411
      char *buf = xmalloc (N * (n + 1));
 
412
      char const *buf_end = buf + N * (n + 1);
 
413
 
 
414
      puts (p);
 
415
      char *z = buf;
 
416
      while (cmp (p, p_len, q, q_len) < 0)
 
417
        {
 
418
          incr (&p, &p_len);
 
419
          z = mempcpy (z, p, p_len);
 
420
          *z++ = *separator;
 
421
          if (buf_end - n - 1 < z)
 
422
            {
 
423
              fwrite (buf, z - buf, 1, stdout);
 
424
              z = buf;
 
425
            }
 
426
        }
 
427
 
 
428
      /* Write any remaining, buffered output.  */
 
429
      if (buf < z)
 
430
        fwrite (buf, z - buf, 1, stdout);
 
431
 
 
432
      IF_LINT (free (buf));
 
433
    }
 
434
 
 
435
  free (p0);
 
436
  free (q0);
 
437
  return ok;
 
438
}
 
439
 
 
440
/* Return true if S consists of at least one digit and no non-digits.  */
 
441
static bool _GL_ATTRIBUTE_PURE
 
442
all_digits_p (char const *s)
 
443
{
 
444
  size_t n = strlen (s);
 
445
  return ISDIGIT (s[0]) && n == strspn (s, "0123456789");
 
446
}
 
447
 
339
448
int
340
449
main (int argc, char **argv)
341
450
{
398
507
        }
399
508
    }
400
509
 
401
 
  if (argc - optind < 1)
 
510
  unsigned int n_args = argc - optind;
 
511
  if (n_args < 1)
402
512
    {
403
513
      error (0, 0, _("missing operand"));
404
514
      usage (EXIT_FAILURE);
405
515
    }
406
516
 
407
 
  if (3 < argc - optind)
 
517
  if (3 < n_args)
408
518
    {
409
519
      error (0, 0, _("extra operand %s"), quote (argv[optind + 3]));
410
520
      usage (EXIT_FAILURE);
413
523
  if (format_str)
414
524
    format_str = long_double_format (format_str, &layout);
415
525
 
 
526
  if (format_str != NULL && equal_width)
 
527
    {
 
528
      error (0, 0, _("format string may not be specified"
 
529
                     " when printing equal width strings"));
 
530
      usage (EXIT_FAILURE);
 
531
    }
 
532
 
 
533
  /* If the following hold:
 
534
     - no format string, [FIXME: relax this, eventually]
 
535
     - integer start (or no start)
 
536
     - integer end
 
537
     - increment == 1 or not specified [FIXME: relax this, eventually]
 
538
     then use the much more efficient integer-only code.  */
 
539
  if (all_digits_p (argv[optind])
 
540
      && (n_args == 1 || all_digits_p (argv[optind + 1]))
 
541
      && (n_args < 3 || STREQ ("1", argv[optind + 2]))
 
542
      && !equal_width && !format_str && strlen (separator) == 1)
 
543
    {
 
544
      char const *s1 = n_args == 1 ? "1" : argv[optind];
 
545
      char const *s2 = n_args == 1 ? argv[optind] : argv[optind + 1];
 
546
      if (seq_fast (s1, s2))
 
547
        exit (EXIT_SUCCESS);
 
548
 
 
549
      /* Upon any failure, let the more general code deal with it.  */
 
550
    }
 
551
 
416
552
  last = scan_arg (argv[optind++]);
417
553
 
418
554
  if (optind < argc)
427
563
        }
428
564
    }
429
565
 
430
 
  if (format_str != NULL && equal_width)
 
566
  if (first.precision == 0 && step.precision == 0 && last.precision == 0
 
567
      && 0 <= first.value && step.value == 1 && 0 <= last.value
 
568
      && !equal_width && !format_str && strlen (separator) == 1)
431
569
    {
432
 
      error (0, 0, _("\
433
 
format string may not be specified when printing equal width strings"));
434
 
      usage (EXIT_FAILURE);
 
570
      char *s1;
 
571
      char *s2;
 
572
      if (asprintf (&s1, "%0.Lf", first.value) < 0)
 
573
        xalloc_die ();
 
574
      if (asprintf (&s2, "%0.Lf", last.value) < 0)
 
575
        xalloc_die ();
 
576
 
 
577
      if (seq_fast (s1, s2))
 
578
        {
 
579
          IF_LINT (free (s1));
 
580
          IF_LINT (free (s2));
 
581
          exit (EXIT_SUCCESS);
 
582
        }
 
583
 
 
584
      free (s1);
 
585
      free (s2);
 
586
      /* Upon any failure, let the more general code deal with it.  */
435
587
    }
436
588
 
437
589
  if (format_str == NULL)