├── .gitignore
├── LICENSE
├── Makefile
├── README.asciidoc
├── Sourcedeps
├── doc
├── txtw.1
└── txtw.1.txt
├── txtw.c
└── txtw.h
/.gitignore:
--------------------------------------------------------------------------------
1 | tags
2 | txtw
3 | *.o
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | NAME = txtw
2 | VERSION = 0.4
3 |
4 | CC ?= gcc
5 | LIBS = -lm -lcairo
6 | CFLAGS += -std=c99 -pedantic -Wall -Wextra -I$(PREFIX)/include
7 | CFLAGS += -D_POSIX_C_SOURCE=200112L -DVERSION=\"$(VERSION)\"
8 | LDFLAGS += -L$(PREFIX)/lib
9 |
10 | PREFIX ?= /usr/local
11 | BINPREFIX = $(PREFIX)/bin
12 | MANPREFIX = $(PREFIX)/share/man
13 |
14 | SRC = $(wildcard *.c)
15 | OBJ = $(SRC:.c=.o)
16 |
17 | all: CFLAGS += -Os
18 | all: LDFLAGS += -s
19 | all: $(NAME)
20 |
21 | include Sourcedeps
22 |
23 | $(OBJ): Makefile
24 |
25 | .c.o:
26 | $(CC) $(CFLAGS) -c -o $@ $<
27 |
28 | $(NAME): $(OBJ)
29 | $(CC) -o $@ $(OBJ) $(LDFLAGS) $(LIBS)
30 |
31 | install:
32 | mkdir -p "$(DESTDIR)$(BINPREFIX)"
33 | cp -p $(NAME) "$(DESTDIR)$(BINPREFIX)"
34 | mkdir -p "$(DESTDIR)$(MANPREFIX)"/man1
35 | cp -p doc/$(NAME).1 "$(DESTDIR)$(MANPREFIX)"/man1
36 |
37 | uninstall:
38 | rm -f "$(DESTDIR)$(BINPREFIX)"/$(NAME)
39 | rm -f "$(DESTDIR)$(MANPREFIX)/"man1/$(NAME).1
40 |
41 | doc:
42 | a2x -v -d manpage -f manpage -a revnumber=$(VERSION) doc/$(NAME).1.txt
43 |
44 | clean:
45 | rm -f $(OBJ) $(NAME)
46 |
47 | .PHONY: all install uninstall doc clean
48 |
--------------------------------------------------------------------------------
/README.asciidoc:
--------------------------------------------------------------------------------
1 | doc/txtw.1.txt
--------------------------------------------------------------------------------
/Sourcedeps:
--------------------------------------------------------------------------------
1 | txtw.o: txtw.c txtw.h
2 |
--------------------------------------------------------------------------------
/doc/txtw.1:
--------------------------------------------------------------------------------
1 | '\" t
2 | .\" Title: txtw
3 | .\" Author: [see the "Author" section]
4 | .\" Generator: DocBook XSL Stylesheets v1.78.1
5 | .\" Date: 12/13/2015
6 | .\" Manual: Txtw Manual
7 | .\" Source: Txtw 0.4
8 | .\" Language: English
9 | .\"
10 | .TH "TXTW" "1" "12/13/2015" "Txtw 0\&.4" "Txtw Manual"
11 | .\" -----------------------------------------------------------------
12 | .\" * Define some portability stuff
13 | .\" -----------------------------------------------------------------
14 | .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15 | .\" http://bugs.debian.org/507673
16 | .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
17 | .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
18 | .ie \n(.g .ds Aq \(aq
19 | .el .ds Aq '
20 | .\" -----------------------------------------------------------------
21 | .\" * set default formatting
22 | .\" -----------------------------------------------------------------
23 | .\" disable hyphenation
24 | .nh
25 | .\" disable justification (adjust text to left margin only)
26 | .ad l
27 | .\" -----------------------------------------------------------------
28 | .\" * MAIN CONTENT STARTS HERE *
29 | .\" -----------------------------------------------------------------
30 | .SH "NAME"
31 | txtw \- Compute text widths
32 | .SH "SYNOPSIS"
33 | .sp
34 | \fBtxtw\fR [\fB\-h\fR|\fB\-v\fR|\fB\-f\fR \fIFONT\fR|\fB\-s\fR \fISIZE\fR|\fB\-F\fR \fIALT_FONT\fR|\fB\-S\fR \fIALT_SIZE\fR] \fISTRING\fR \&...
35 | .SH "DESCRIPTION"
36 | .sp
37 | Returns the width in pixels of the given strings for the the given font\&.
38 | .SH "OPTIONS"
39 | .PP
40 | \fB\-h\fR
41 | .RS 4
42 | Print the synopsis to standard output and exit\&.
43 | .RE
44 | .PP
45 | \fB\-v\fR
46 | .RS 4
47 | Print the version information to standard output and exit\&.
48 | .RE
49 | .PP
50 | \fB\-f\fR \fIFONT\fR
51 | .RS 4
52 | Set the main font\&.
53 | .RE
54 | .PP
55 | \fB\-s\fR \fISIZE\fR
56 | .RS 4
57 | Set the size of the main font\&.
58 | .RE
59 | .PP
60 | \fB\-F\fR \fIALT_FONT\fR
61 | .RS 4
62 | Set the alternate font\&.
63 | .RE
64 | .PP
65 | \fB\-S\fR \fIALT_SIZE\fR
66 | .RS 4
67 | Set the size of the alternate font\&.
68 | .RE
69 | .SH "STRING SYNTAX"
70 | .sp
71 | By default the main font is used to compute the width\&.
72 | .sp
73 | The alternate font is used for the parts of the string enclosed between \fI\e(\fR and \fI\e)\fR\&.
74 | .SH "EXAMPLE"
75 | .sp
76 | .if n \{\
77 | .RS 4
78 | .\}
79 | .nf
80 | txtw \-f \*(AqDejaVu Sans\*(Aq \-s 11 \-F SimpleIcons \-S 16 \*(AqOne \e(U\e) Two \e(D\e) Three\*(Aq
81 | .fi
82 | .if n \{\
83 | .RE
84 | .\}
85 | .SH "AUTHOR"
86 | .sp
87 | Bastien Dejean
88 |
--------------------------------------------------------------------------------
/doc/txtw.1.txt:
--------------------------------------------------------------------------------
1 | :man source: Txtw
2 | :man version: {revnumber}
3 | :man manual: Txtw Manual
4 |
5 | txtw(1)
6 | =======
7 |
8 | Name
9 | ----
10 |
11 | txtw - Compute text widths
12 |
13 | Synopsis
14 | --------
15 |
16 | *txtw* [*-h*|*-v*|*-f* _FONT_|*-s* _SIZE_|*-F* _ALT_FONT_|*-S* _ALT_SIZE_] _STRING_ ...
17 |
18 | Description
19 | -----------
20 |
21 | Returns the width in pixels of the given strings for the the given font.
22 |
23 | Options
24 | -------
25 |
26 | *-h*::
27 | Print the synopsis to standard output and exit.
28 |
29 | *-v*::
30 | Print the version information to standard output and exit.
31 |
32 | *-f* _FONT_::
33 | Set the main font.
34 |
35 | *-s* _SIZE_::
36 | Set the size of the main font.
37 |
38 | *-F* _ALT_FONT_::
39 | Set the alternate font.
40 |
41 | *-S* _ALT_SIZE_::
42 | Set the size of the alternate font.
43 |
44 | String Syntax
45 | -------------
46 |
47 | By default the main font is used to compute the width.
48 |
49 | The alternate font is used for the parts of the string enclosed between _\(_ and _\)_.
50 |
51 | Example
52 | -------
53 |
54 | ----
55 | txtw -f 'DejaVu Sans' -s 11 -F SimpleIcons -S 16 'One \(U\) Two \(D\) Three'
56 | ----
57 |
58 | Author
59 | ------
60 |
61 | Bastien Dejean
62 |
63 | ////
64 | vim: set ft=asciidoc:
65 | ////
66 |
--------------------------------------------------------------------------------
/txtw.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include "txtw.h"
8 |
9 | int text_width(char *font_family, int font_size, char *s) {
10 | cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 1, 1);
11 | cairo_t *cr = cairo_create(surface);
12 | cairo_text_extents_t te;
13 | cairo_select_font_face(cr, font_family, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
14 | cairo_set_font_size(cr, font_size);
15 | cairo_text_extents(cr, s, &te);
16 | int width = te.x_advance;
17 | cairo_destroy(cr);
18 | cairo_surface_destroy(surface);
19 | return width;
20 | }
21 |
22 | int main(int argc, char *argv[]) {
23 | char font_family[MAXLEN] = FONT_FAMILY;
24 | int font_size = FONT_SIZE;
25 | char *alt_font_family = NULL;
26 | int alt_font_size = FONT_SIZE;
27 | int opt;
28 |
29 | while ((opt = getopt(argc, argv, "hvf:s:F:S:")) != -1) {
30 | switch (opt) {
31 | case 'h':
32 | printf("textwidth [-h|-v|-f FONT|-s SIZE|-F ALT_FONT|-S ALT_SIZE] STRING ...\n");
33 | return EXIT_SUCCESS;
34 | break;
35 | case 'v':
36 | printf("%s\n", VERSION);
37 | return EXIT_SUCCESS;
38 | break;
39 | case 'f':
40 | strncpy(font_family, optarg, sizeof(font_family));
41 | font_family[MIN(sizeof(font_family), strlen(optarg))] = '\0';
42 | break;
43 | case 's':
44 | font_size = atoi(optarg);
45 | break;
46 | case 'F':
47 | alt_font_family = optarg;
48 | break;
49 | case 'S':
50 | alt_font_size = atoi(optarg);
51 | break;
52 | }
53 | }
54 |
55 | int num = argc - optind;
56 | char **args = argv + optind;
57 |
58 | if (alt_font_family == NULL) {
59 | for (int i = 0; i < num; i++)
60 | printf("%i%s", text_width(font_family, font_size, args[i]), i < (num - 1) ? " " : "\n");
61 | } else {
62 | char chunk[MAXLEN] = {0};
63 | for (int i = 0; i < num; i++) {
64 | char *s = args[i];
65 | unsigned int j = 0, pos = 0, w = 0;
66 | bool opa = false;
67 | while (j < strlen(s) && pos < sizeof(chunk)) {
68 | if (s[j] == ALT_MAGIC_CHAR) {
69 | if (s[j + 1] == ALT_BEGIN_SEQ && !opa) {
70 | chunk[pos] = '\0';
71 | w += text_width(font_family, font_size, chunk);
72 | opa = true;
73 | pos = 0;
74 | j += 2;
75 | } else if (s[j + 1] == ALT_END_SEQ && opa) {
76 | chunk[pos] = '\0';
77 | w += text_width(alt_font_family, alt_font_size, chunk);
78 | opa = false;
79 | pos = 0;
80 | j += 2;
81 | } else if (s[j + 1] == ALT_MAGIC_CHAR) {
82 | chunk[pos++] = ALT_MAGIC_CHAR;
83 | j += 2;
84 | } else {
85 | chunk[pos++] = s[j++];
86 | }
87 | } else {
88 | chunk[pos++] = s[j++];
89 | }
90 | }
91 | chunk[pos] = '\0';
92 | if (opa)
93 | w += text_width(alt_font_family, alt_font_size, chunk);
94 | else
95 | w += text_width(font_family, font_size, chunk);
96 | printf("%i%s", w, i < (num - 1) ? " " : "\n");
97 | }
98 | }
99 |
100 | return EXIT_SUCCESS;
101 | }
102 |
--------------------------------------------------------------------------------
/txtw.h:
--------------------------------------------------------------------------------
1 | #ifndef _TXTW_H
2 | #define _TXTW_H
3 |
4 | #define FONT_FAMILY "sans-serif"
5 | #define FONT_SIZE 16
6 | #define ALT_MAGIC_CHAR '\\'
7 | #define ALT_BEGIN_SEQ '('
8 | #define ALT_END_SEQ ')'
9 | #define MAXLEN 256
10 | #define MIN(A, B) ((A) < (B) ? (A) : (B))
11 |
12 | int text_width(char *, int, char *);
13 |
14 | #endif
15 |
--------------------------------------------------------------------------------