~q3cpma/misc-tools

ref: 0695c6188d0f70c89d8e1757f2463b2e3869a60a misc-tools/mbcut.c -rw-r--r-- 2.2 KiB
0695c618q3cpma htmldecode: move to root, use genhtab instead of lex 1 year, 4 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#define _XOPEN_SOURCE /* wcwidth */

#include <getopt.h>
#include <locale.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>

#include "misc.h"
#include "utf8.h"

#define ELLIPSIS		  L'…'
#define ELLIPSIS_FALLBACK '$'


NORETURN void usage(int exit_status)
{
	printf(
		"NAME\n"
		"    %s - Multibyte aware string trimming\n"
		"\n"
		"SYNOPSIS\n"
		"    %s [-OPTIONS] STRING LENGTH\n"
		"\n"
		"DESCRIPTION\n"
		"    Trim STRING to fit into LENGTH columns then print it to stdout.\n"
		"\n"
		"OPTIONS\n"
		"    -e\n"
		"        Add an ellipsis at the end of output if the string is "
		"trimmed.\n"
		"        A dollar is used instead when unicode isn't supported.\n"
		"\n"
		"    -h\n"
		"        Print this help message and exit.\n"
		"\n"
		"    -v\n"
		"        Print the version and exit.\n"
		"\n",
		PROG_NAME, PROG_NAME);
	exit(exit_status);
}

int main(int argc, char **argv)
{
	signals_nointerrupt();

	bool ellipsis = false;
	for (int opt; (opt = getopt(argc, argv, "ehv")) != -1;)
	{
		switch (opt)
		{
			case 'h':
				usage(EXIT_SUCCESS);
				break;

			case 'e':
				ellipsis = true;
				break;

			case 'v':
			    puts(PROG_VERSION);
				exit(EXIT_SUCCESS);

			default:
				usage(EXIT_FAILURE);
		}
	}
	if (argc - optind != 2)
	{
		usage(EXIT_FAILURE);
	}

	if (!setlocale(LC_ALL, ""))
	{
		die("Couldn't set locale");
	}

	const char *p = argv[optind];
	const size_t arglen = strlen(argv[optind]);
	const int64_t cutlen = xstrtoul(argv[optind + 1], 10);

	if ((int64_t)arglen * 2 < cutlen)
	{
		puts(argv[optind]);
	    return EXIT_SUCCESS;
	}
	if (cutlen == 0)
	{
		putchar('\n');
	    return EXIT_SUCCESS;
	}

	uint32_t c = xutf8_decode_step(&p);
	int64_t len = codep_width(c);

	for (; c; c = xutf8_decode_step(&p), len += codep_width(c))
	{
		if (len > cutlen)
		{
			utf8_unstep(&p);
			//Make some place for the ellipsis
			if (ellipsis && len - codep_width(c) == cutlen)
			{
				utf8_unstep(&p);
			}
			break;
		}
	}

	printf("%.*s", (int)(p - argv[optind]), argv[optind]);
	if (ellipsis && len > cutlen)
	{
	    printf("%lc", wcwidth(ELLIPSIS) == 1 ? ELLIPSIS : ELLIPSIS_FALLBACK);
	}
	putchar('\n');
	return EXIT_SUCCESS;
}