~ubuntu-branches/ubuntu/trusty/util-linux/trusty-proposed

« back to all changes in this revision

Viewing changes to text-utils/ul.c

  • Committer: Package Import Robot
  • Author(s): LaMont Jones
  • Date: 2011-11-03 15:38:23 UTC
  • mto: (4.5.5 sid) (1.6.4)
  • mto: This revision was merged to the branch mainline in revision 85.
  • Revision ID: package-import@ubuntu.com-20111103153823-10sx16jprzxlhkqf
ImportĀ upstreamĀ versionĀ 2.20.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
47
47
#include <stdlib.h>             /* for getenv() */
48
48
#include <limits.h>             /* for INT_MAX */
49
49
#include <signal.h>             /* for signal() */
50
 
#include <err.h>
51
50
#include <errno.h>
 
51
#include <getopt.h>
52
52
 
53
53
#include "nls.h"
54
54
#include "xalloc.h"
55
55
#include "widechar.h"
 
56
#include "c.h"
56
57
 
57
58
#ifdef HAVE_WIDECHAR
58
 
static int put1wc(int c) /* Output an ASCII character as a wide character */
 
59
/* Output an ASCII character as a wide character */
 
60
static int put1wc(int c)
59
61
{
60
 
  if (putwchar(c) == WEOF)
61
 
    return EOF;
62
 
  else
63
 
    return c;
 
62
        if (putwchar(c) == WEOF)
 
63
                return EOF;
 
64
        else
 
65
                return c;
64
66
}
65
 
#define putwp(s) tputs(s,1,put1wc)
 
67
#define putwp(s) tputs(s, STDOUT_FILENO, put1wc)
66
68
#else
67
69
#define putwp(s) putp(s)
68
70
#endif
69
71
 
70
 
void filter(FILE *f);
71
 
void flushln(void);
72
 
void overstrike(void);
73
 
void iattr(void);
74
 
void initbuf(void);
75
 
void fwd(void);
76
 
void reverse(void);
77
 
void initinfo(void);
78
 
void outc(wint_t c, int width);
79
 
void setmode(int newmode);
 
72
static void usage(FILE *out);
 
73
static int handle_escape(FILE * f);
 
74
static void filter(FILE *f);
 
75
static void flushln(void);
 
76
static void overstrike(void);
 
77
static void iattr(void);
 
78
static void initbuf(void);
 
79
static void fwd(void);
 
80
static void reverse(void);
 
81
static void initinfo(void);
 
82
static void outc(wint_t c, int width);
 
83
static void setmode(int newmode);
80
84
static void setcol(int newcol);
81
85
static void needcol(int col);
82
86
static void sig_handler(int signo);
 
87
static void print_out(char *line);
83
88
 
84
89
#define IESC    '\033'
85
90
#define SO      '\016'
94
99
#define SUBSC   004     /* Dim | Ul */
95
100
#define UNDERL  010     /* Ul */
96
101
#define BOLD    020     /* Bold */
97
 
#define INITBUF 512
98
102
 
99
103
int     must_use_uc, must_overstrike;
100
 
char    *CURS_UP, *CURS_RIGHT, *CURS_LEFT,
101
 
        *ENTER_STANDOUT, *EXIT_STANDOUT, *ENTER_UNDERLINE, *EXIT_UNDERLINE,
102
 
        *ENTER_DIM, *ENTER_BOLD, *ENTER_REVERSE, *UNDER_CHAR, *EXIT_ATTRIBUTES;
 
104
char    *CURS_UP,
 
105
        *CURS_RIGHT,
 
106
        *CURS_LEFT,
 
107
        *ENTER_STANDOUT,
 
108
        *EXIT_STANDOUT,
 
109
        *ENTER_UNDERLINE,
 
110
        *EXIT_UNDERLINE,
 
111
        *ENTER_DIM,
 
112
        *ENTER_BOLD,
 
113
        *ENTER_REVERSE,
 
114
        *UNDER_CHAR,
 
115
        *EXIT_ATTRIBUTES;
103
116
 
104
117
struct  CHAR    {
105
118
        char    c_mode;
106
119
        wchar_t c_char;
107
120
        int     c_width;
108
 
} ;
 
121
};
109
122
 
110
123
struct  CHAR    *obuf;
111
 
int     obuflen;                /* Tracks number of elements in obuf. */
 
124
int     obuflen;
112
125
int     col, maxcol;
113
126
int     mode;
114
127
int     halfpos;
115
128
int     upln;
116
129
int     iflag;
117
130
 
118
 
#define PRINT(s)        if (s == NULL) /* void */; else putwp(s)
 
131
static void __attribute__((__noreturn__))
 
132
usage(FILE *out)
 
133
{
 
134
        fprintf(out, _(
 
135
                "\nUsage:\n"
 
136
                " %s [options] [file...]\n"), program_invocation_short_name);
 
137
 
 
138
        fprintf(out, _(
 
139
                "\nOptions:\n"
 
140
                " -t, --terminal TERMINAL    override the TERM environment variable\n"
 
141
                " -i, --indicated            underlining is indicated via a separate line\n"
 
142
                " -V, --version              output version information and exit\n"
 
143
                " -h, --help                 display this help and exit\n\n"));
 
144
 
 
145
        exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
 
146
}
119
147
 
120
148
int main(int argc, char **argv)
121
149
{
122
 
        int c, ret;
 
150
        int c, ret, tflag = 0;
123
151
        char *termtype;
124
152
        FILE *f;
125
153
 
 
154
        static const struct option longopts[] = {
 
155
                { "terminal",   required_argument,      0, 't' },
 
156
                { "indicated",  no_argument,            0, 'i' },
 
157
                { "version",    no_argument,            0, 'V' },
 
158
                { "help",       no_argument,            0, 'h' },
 
159
                { NULL, 0, 0, 0 }
 
160
        };
 
161
 
126
162
        setlocale(LC_ALL, "");
127
163
        bindtextdomain(PACKAGE, LOCALEDIR);
128
164
        textdomain(PACKAGE);
131
167
        signal(SIGTERM, sig_handler);
132
168
 
133
169
        termtype = getenv("TERM");
134
 
        if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1)))
 
170
 
 
171
        /*
 
172
         * FIXME: why terminal type is lpr when command begins with c and has
 
173
         * no terminal? If this behavior can be explained please insert
 
174
         * refrence or remove the code. In case this truly is desired command
 
175
         * behavior this should be mentioned in manual page.
 
176
         */
 
177
        if (termtype == NULL || (argv[0][0] == 'c' && !isatty(STDOUT_FILENO)))
135
178
                termtype = "lpr";
136
 
        while ((c = getopt(argc, argv, "it:T:")) != -1)
137
 
                switch(c) {
 
179
 
 
180
        while ((c = getopt_long(argc, argv, "it:T:Vh", longopts, NULL)) != -1)
 
181
                switch (c) {
138
182
 
139
183
                case 't':
140
 
                case 'T': /* for nroff compatibility */
141
 
                                termtype = optarg;
 
184
                case 'T':
 
185
                        /* for nroff compatibility */
 
186
                        termtype = optarg;
 
187
                        tflag = 1;
142
188
                        break;
143
189
                case 'i':
144
190
                        iflag = 1;
145
191
                        break;
146
 
 
 
192
                case 'V':
 
193
                        printf(_("%s from %s\n"), program_invocation_short_name,
 
194
                                                  PACKAGE_STRING);
 
195
                        return EXIT_SUCCESS;
 
196
                case 'h':
 
197
                        usage(stdout);
147
198
                default:
148
 
                        fprintf(stderr,
149
 
                                _("Usage: %s [ -i ] [ -tTerm ] file...\n"),
150
 
                                program_invocation_short_name);
151
 
                        return EXIT_FAILURE;
 
199
                        usage(stderr);
152
200
                }
153
 
        setupterm(termtype, 1, &ret);
154
 
        switch(ret) {
 
201
        setupterm(termtype, STDOUT_FILENO, &ret);
 
202
        switch (ret) {
155
203
 
156
204
        case 1:
157
205
                break;
161
209
                /* fall through to ... */
162
210
 
163
211
        case 0:
164
 
                /* No such terminal type - assume dumb */
165
 
                setupterm("dumb", 1, (int *)0);
 
212
                if (tflag)
 
213
                        warnx(_("terminal `%s' is not known, defaulting to `dumb'"),
 
214
                                termtype);
 
215
                setupterm("dumb", STDOUT_FILENO, (int *)0);
166
216
                break;
167
217
        }
168
218
        initinfo();
169
 
        if (    (tigetflag("os") && ENTER_BOLD==NULL ) ||
170
 
                (tigetflag("ul") && ENTER_UNDERLINE==NULL && UNDER_CHAR==NULL))
171
 
                        must_overstrike = 1;
 
219
        if ((tigetflag("os") && ENTER_BOLD==NULL ) ||
 
220
            (tigetflag("ul") && ENTER_UNDERLINE==NULL && UNDER_CHAR==NULL))
 
221
                must_overstrike = 1;
172
222
        initbuf();
173
223
        if (optind == argc)
174
224
                filter(stdin);
175
 
        else for (; optind<argc; optind++) {
176
 
                f = fopen(argv[optind],"r");
177
 
                if (!f)
178
 
                        err(EXIT_FAILURE, _("%s: open failed"), argv[optind]);
179
 
                filter(f);
180
 
        }
 
225
        else
 
226
                for (; optind < argc; optind++) {
 
227
                        f = fopen(argv[optind],"r");
 
228
                        if (!f)
 
229
                                err(EXIT_FAILURE, _("%s: open failed"),
 
230
                                    argv[optind]);
 
231
                        filter(f);
 
232
                        fclose(f);
 
233
                }
181
234
        if (ferror(stdout) || fclose(stdout))
182
235
                return EXIT_FAILURE;
183
236
 
 
237
        free(obuf);
184
238
        return EXIT_SUCCESS;
185
239
}
186
240
 
187
 
void filter(FILE *f)
 
241
static int handle_escape(FILE * f)
 
242
{
 
243
        wint_t c;
 
244
 
 
245
        switch (c = getwc(f)) {
 
246
        case HREV:
 
247
                if (halfpos == 0) {
 
248
                        mode |= SUPERSC;
 
249
                        halfpos--;
 
250
                } else if (halfpos > 0) {
 
251
                        mode &= ~SUBSC;
 
252
                        halfpos--;
 
253
                } else {
 
254
                        halfpos = 0;
 
255
                        reverse();
 
256
                }
 
257
                return 0;
 
258
        case HFWD:
 
259
                if (halfpos == 0) {
 
260
                        mode |= SUBSC;
 
261
                        halfpos++;
 
262
                } else if (halfpos < 0) {
 
263
                        mode &= ~SUPERSC;
 
264
                        halfpos++;
 
265
                } else {
 
266
                        halfpos = 0;
 
267
                        fwd();
 
268
                }
 
269
                return 0;
 
270
        case FREV:
 
271
                reverse();
 
272
                return 0;
 
273
        default:
 
274
                /* unknown escape */
 
275
                ungetwc(c, f);
 
276
                return 1;
 
277
        }
 
278
}
 
279
 
 
280
static void filter(FILE *f)
188
281
{
189
282
        wint_t c;
190
283
        int i, w;
191
284
 
192
 
        while ((c = getwc(f)) != WEOF) switch(c) {
 
285
        while ((c = getwc(f)) != WEOF)
 
286
        switch (c) {
193
287
 
194
288
        case '\b':
195
289
                setcol(col - 1);
212
306
                continue;
213
307
 
214
308
        case IESC:
215
 
                switch (c = getwc(f)) {
216
 
 
217
 
                case HREV:
218
 
                        if (halfpos == 0) {
219
 
                                mode |= SUPERSC;
220
 
                                halfpos--;
221
 
                        } else if (halfpos > 0) {
222
 
                                mode &= ~SUBSC;
223
 
                                halfpos--;
224
 
                        } else {
225
 
                                halfpos = 0;
226
 
                                reverse();
227
 
                        }
228
 
                        continue;
229
 
 
230
 
                case HFWD:
231
 
                        if (halfpos == 0) {
232
 
                                mode |= SUBSC;
233
 
                                halfpos++;
234
 
                        } else if (halfpos < 0) {
235
 
                                mode &= ~SUPERSC;
236
 
                                halfpos++;
237
 
                        } else {
238
 
                                halfpos = 0;
239
 
                                fwd();
240
 
                        }
241
 
                        continue;
242
 
 
243
 
                case FREV:
244
 
                        reverse();
245
 
                        continue;
246
 
 
247
 
                default:
 
309
                if(handle_escape(f)) {
 
310
                        c = getwc(f);
248
311
                        errx(EXIT_FAILURE,
249
312
                                _("unknown escape sequence in input: %o, %o"),
250
313
                                IESC, c);
251
 
                        break;
252
314
                }
253
315
                continue;
254
316
 
279
341
                continue;
280
342
 
281
343
        default:
282
 
                if (!iswprint(c))       /* non printing */
 
344
                if (!iswprint(c))
 
345
                        /* non printable */
283
346
                        continue;
284
347
                w = wcwidth(c);
285
348
                needcol(col + w);
297
360
                        obuf[col].c_width = w;
298
361
                        for (i = 1; i < w; i++)
299
362
                                obuf[col+i].c_width = -1;
300
 
                } else if (obuf[col].c_char == c) {
 
363
                } else if ((wint_t) obuf[col].c_char == c) {
301
364
                        for (i = 0; i < w; i++)
302
365
                                obuf[col+i].c_mode |= BOLD|mode;
303
366
                } else {
312
375
                flushln();
313
376
}
314
377
 
315
 
void flushln(void)
 
378
static void flushln(void)
316
379
{
317
380
        int lastmode;
318
381
        int i;
319
382
        int hadmodes = 0;
320
383
 
321
384
        lastmode = NORMAL;
322
 
        for (i=0; i<maxcol; i++) {
 
385
        for (i = 0; i < maxcol; i++) {
323
386
                if (obuf[i].c_mode != lastmode) {
324
387
                        hadmodes++;
325
388
                        setmode(obuf[i].c_mode);
327
390
                }
328
391
                if (obuf[i].c_char == '\0') {
329
392
                        if (upln) {
330
 
                                PRINT(CURS_RIGHT);
 
393
                                print_out(CURS_RIGHT);
331
394
                        } else
332
395
                                outc(' ', 1);
333
396
                } else
334
397
                        outc(obuf[i].c_char, obuf[i].c_width);
335
398
                if (obuf[i].c_width > 1)
336
 
                        i += obuf[i].c_width -1;
 
399
                        i += obuf[i].c_width - 1;
337
400
        }
338
401
        if (lastmode != NORMAL) {
339
402
                setmode(0);
343
406
        putwchar('\n');
344
407
        if (iflag && hadmodes)
345
408
                iattr();
346
 
        (void)fflush(stdout);
 
409
        fflush(stdout);
347
410
        if (upln)
348
411
                upln--;
349
412
        initbuf();
353
416
 * For terminals that can overstrike, overstrike underlines and bolds.
354
417
 * We don't do anything with halfline ups and downs, or Greek.
355
418
 */
356
 
void overstrike(void)
 
419
static void overstrike(void)
357
420
{
358
421
        register int i;
359
422
#ifdef __GNUC__
360
 
        register wchar_t *lbuf = __builtin_alloca((maxcol+1)*sizeof(wchar_t));
 
423
        register wchar_t *lbuf = __builtin_alloca((maxcol + 1) * sizeof(wchar_t));
361
424
#else
362
 
        wchar_t lbuf[256];
 
425
        wchar_t lbuf[BUFSIZ];
363
426
#endif
364
427
        register wchar_t *cp = lbuf;
365
428
        int hadbold=0;
366
429
 
367
430
        /* Set up overstrike buffer */
368
 
        for (i=0; i<maxcol; i++)
 
431
        for (i = 0; i < maxcol; i++)
369
432
                switch (obuf[i].c_mode) {
370
433
                case NORMAL:
371
434
                default:
382
445
                        break;
383
446
                }
384
447
        putwchar('\r');
385
 
        for (*cp=' '; *cp==' '; cp--)
 
448
        for (*cp = ' '; *cp == ' '; cp--)
386
449
                *cp = 0;
387
 
        for (cp=lbuf; *cp; cp++)
 
450
        for (cp = lbuf; *cp; cp++)
388
451
                putwchar(*cp);
389
452
        if (hadbold) {
390
453
                putwchar('\r');
391
 
                for (cp=lbuf; *cp; cp++)
392
 
                        putwchar(*cp=='_' ? ' ' : *cp);
 
454
                for (cp = lbuf; *cp; cp++)
 
455
                        putwchar(*cp == '_' ? ' ' : *cp);
393
456
                putwchar('\r');
394
 
                for (cp=lbuf; *cp; cp++)
395
 
                        putwchar(*cp=='_' ? ' ' : *cp);
 
457
                for (cp = lbuf; *cp; cp++)
 
458
                        putwchar(*cp == '_' ? ' ' : *cp);
396
459
        }
397
460
}
398
461
 
399
 
void iattr(void)
 
462
static void iattr(void)
400
463
{
401
464
        register int i;
402
465
#ifdef __GNUC__
403
466
        register char *lbuf = __builtin_alloca((maxcol+1)*sizeof(char));
404
467
#else
405
 
        char lbuf[256];
 
468
        char lbuf[BUFSIZ];
406
469
#endif
407
470
        register char *cp = lbuf;
408
471
 
409
 
        for (i=0; i<maxcol; i++)
 
472
        for (i = 0; i < maxcol; i++)
410
473
                switch (obuf[i].c_mode) {
411
474
                case NORMAL:    *cp++ = ' '; break;
412
475
                case ALTSET:    *cp++ = 'g'; break;
416
479
                case BOLD:      *cp++ = '!'; break;
417
480
                default:        *cp++ = 'X'; break;
418
481
                }
419
 
        for (*cp=' '; *cp==' '; cp--)
 
482
        for (*cp = ' '; *cp == ' '; cp--)
420
483
                *cp = 0;
421
 
        for (cp=lbuf; *cp; cp++)
 
484
        for (cp = lbuf; *cp; cp++)
422
485
                putwchar(*cp);
423
486
        putwchar('\n');
424
487
}
425
488
 
426
 
void initbuf(void)
 
489
static void initbuf(void)
427
490
{
428
 
        if (obuf == NULL) {     /* First time. */
429
 
                obuflen = INITBUF;
 
491
        if (obuf == NULL) {
 
492
                /* First time. */
 
493
                obuflen = BUFSIZ;
430
494
                obuf = xmalloc(sizeof(struct CHAR) * obuflen);
431
495
        }
432
496
 
437
501
        mode &= ALTSET;
438
502
}
439
503
 
440
 
void fwd(void)
 
504
static void fwd(void)
441
505
{
442
506
        int oldcol, oldmax;
443
507
 
448
512
        maxcol = oldmax;
449
513
}
450
514
 
451
 
void reverse(void)
 
515
static void reverse(void)
452
516
{
453
517
        upln++;
454
518
        fwd();
455
 
        PRINT(CURS_UP);
456
 
        PRINT(CURS_UP);
 
519
        print_out(CURS_UP);
 
520
        print_out(CURS_UP);
457
521
        upln++;
458
522
}
459
523
 
460
 
void initinfo(void)
 
524
static void initinfo(void)
461
525
{
462
526
        CURS_UP =               tigetstr("cuu1");
463
527
        CURS_RIGHT =            tigetstr("cuf1");
503
567
 
504
568
static int curmode = 0;
505
569
 
506
 
void
507
 
outc(wint_t c, int width) {
 
570
static void outc(wint_t c, int width) {
508
571
        int i;
509
572
 
510
573
        putwchar(c);
511
574
        if (must_use_uc && (curmode&UNDERL)) {
512
 
                for (i=0; i<width; i++)
513
 
                        PRINT(CURS_LEFT);
514
 
                for (i=0; i<width; i++)
515
 
                        PRINT(UNDER_CHAR);
 
575
                for (i = 0; i < width; i++)
 
576
                        print_out(CURS_LEFT);
 
577
                for (i = 0; i < width; i++)
 
578
                        print_out(UNDER_CHAR);
516
579
        }
517
580
}
518
581
 
519
 
void setmode(int newmode)
 
582
static void setmode(int newmode)
520
583
{
521
584
        if (!iflag) {
522
585
                if (curmode != NORMAL && newmode != NORMAL)
523
586
                        setmode(NORMAL);
524
587
                switch (newmode) {
525
588
                case NORMAL:
526
 
                        switch(curmode) {
 
589
                        switch (curmode) {
527
590
                        case NORMAL:
528
591
                                break;
529
592
                        case UNDERL:
530
 
                                PRINT(EXIT_UNDERLINE);
 
593
                                print_out(EXIT_UNDERLINE);
531
594
                                break;
532
595
                        default:
533
596
                                /* This includes standout */
534
 
                                PRINT(EXIT_ATTRIBUTES);
 
597
                                print_out(EXIT_ATTRIBUTES);
535
598
                                break;
536
599
                        }
537
600
                        break;
538
601
                case ALTSET:
539
 
                        PRINT(ENTER_REVERSE);
 
602
                        print_out(ENTER_REVERSE);
540
603
                        break;
541
604
                case SUPERSC:
542
605
                        /*
543
606
                         * This only works on a few terminals.
544
607
                         * It should be fixed.
545
608
                         */
546
 
                        PRINT(ENTER_UNDERLINE);
547
 
                        PRINT(ENTER_DIM);
 
609
                        print_out(ENTER_UNDERLINE);
 
610
                        print_out(ENTER_DIM);
548
611
                        break;
549
612
                case SUBSC:
550
 
                        PRINT(ENTER_DIM);
 
613
                        print_out(ENTER_DIM);
551
614
                        break;
552
615
                case UNDERL:
553
 
                        PRINT(ENTER_UNDERLINE);
 
616
                        print_out(ENTER_UNDERLINE);
554
617
                        break;
555
618
                case BOLD:
556
 
                        PRINT(ENTER_BOLD);
 
619
                        print_out(ENTER_BOLD);
557
620
                        break;
558
621
                default:
559
622
                        /*
560
623
                         * We should have some provision here for multiple modes
561
624
                         * on at once.  This will have to come later.
562
625
                         */
563
 
                        PRINT(ENTER_STANDOUT);
 
626
                        print_out(ENTER_STANDOUT);
564
627
                        break;
565
628
                }
566
629
        }
567
630
        curmode = newmode;
568
631
}
569
632
 
570
 
static void
571
 
setcol(int newcol) {
 
633
static void setcol(int newcol) {
572
634
        col = newcol;
573
635
 
574
636
        if (col < 0)
577
639
                needcol(col);
578
640
}
579
641
 
580
 
static void
581
 
needcol(int col) {
 
642
static void needcol(int col) {
582
643
        maxcol = col;
583
644
 
584
645
        /* If col >= obuflen, expand obuf until obuflen > col. */
588
649
                        errx(EXIT_FAILURE, _("Input line too long."));
589
650
 
590
651
                /* Similar paranoia: double only up to INT_MAX. */
591
 
                obuflen = ((INT_MAX / 2) < obuflen)
592
 
                        ? INT_MAX
593
 
                        : obuflen * 2;
 
652
                if (obuflen < (INT_MAX / 2))
 
653
                        obuflen *= 2;
 
654
                else
 
655
                        obuflen = INT_MAX;
594
656
 
595
657
                /* Now we can try to expand obuf. */
596
658
                obuf = xrealloc(obuf, sizeof(struct CHAR) * obuflen);
597
659
        }
598
660
}
599
661
 
600
 
static void sig_handler(int signo)
 
662
static void sig_handler(int signo __attribute__ ((__unused__)))
601
663
{
602
664
        _exit(EXIT_SUCCESS);
603
665
}
604
666
 
 
667
static void print_out(char *line)
 
668
{
 
669
        if (line == NULL)
 
670
                return;
 
671
 
 
672
        putwp(line);
 
673
}