├── .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 | --------------------------------------------------------------------------------