std::string convert_and_ellipsize(std::string s, int len) {
	if (s.find('<') == 0) {
		int e = s.find('>');
		std::stringstream ss;
		ss << "<span foreground=\"#" << font::color2hexa(font::markup2color(s.substr(1, e - 1))) << "\">";
		ss << ellipsize(s.substr(e + 1), len);
		ss << "</span>";
		return ss.str();
	} else {
		return ellipsize(s, len);
	}
}
Exemple #2
0
static void centerstring (Rect r, Str255 s) {
	
	/*
	draw the string in the current font, size and style, centered inside
	the indicated rectangle.
	*/
	
	short rh = r.bottom - r.top;
	short rw = r.right - r.left;
	short h, v;
	FontInfo fi;
	
	GetFontInfo (&fi);
	
	ellipsize (s, rw); /*make sure it fits inside the rectangle, width-wise*/
	
	h = r.left + ((rw - StringWidth (s)) / 2);
	
	v = r.top + ((rh - (fi.ascent + fi.descent)) / 2) + fi.ascent;
	
	MoveTo (h, v);
	
	ClipRect (&r);
	
	DrawString (s);
	} /*centerstring*/
Exemple #3
0
static void
log_accessible (EventLog *log, Accessible *accessible)
{
	GtkTextTag *tag;
	GtkTextIter iter;
	char *text, *name, *descr, *short_descr;
	char *role_name, *ifaces;

	if (!accessible) {
		log_message (log, "<Null>");
		return;
	}

	tag = gtk_text_buffer_create_tag (log->log_text, NULL, 
					  "foreground", "blue", 
					  "underline", PANGO_UNDERLINE_SINGLE, 
					  NULL);
	Accessible_ref (accessible);
	g_object_set_data_full (G_OBJECT (tag), "accessible", accessible,
				(GDestroyNotify) Accessible_unref );

	ifaces = accessible_get_iface_string (accessible);
	role_name = Accessible_getRoleName (accessible);
	name = Accessible_getName (accessible);
	descr = Accessible_getDescription (accessible);
	short_descr = ellipsize (descr);

	/* FIXME: nice mangled printout of supported interfaces ? */
	text = g_strdup_printf ("%s:%s:%s:%s",
				ifaces,
				role_name ? role_name : "--",
				name ? name : "--",
				short_descr ? short_descr : "--");

	gtk_text_buffer_get_end_iter (log->log_text, &iter);
	gtk_text_buffer_insert_with_tags (log->log_text, &iter, text, -1, tag, NULL);

	g_free (text);
	g_free (short_descr);
	SPI_freeString (descr);
	SPI_freeString (name);
	SPI_freeString (role_name);
	g_free (ifaces);

	log_track_end (log);
}
Exemple #4
0
static int show_menu(char **x, unsigned n_columns, unsigned width, unsigned percentage) {
        unsigned n, per_column, i, j;
        unsigned break_lines, break_modulo;

        assert(n_columns > 0);

        n = strv_length(x);
        per_column = (n + n_columns - 1) / n_columns;

        break_lines = lines();
        if (break_lines > 2)
                break_lines--;

        /* The first page gets two extra lines, since we want to show
         * a title */
        break_modulo = break_lines;
        if (break_modulo > 3)
                break_modulo -= 3;

        for (i = 0; i < per_column; i++) {

                for (j = 0; j < n_columns; j ++) {
                        _cleanup_free_ char *e = NULL;

                        if (j * per_column + i >= n)
                                break;

                        e = ellipsize(x[j * per_column + i], width, percentage);
                        if (!e)
                                return log_oom();

                        printf("%4u) %-*s", j * per_column + i + 1, width, e);
                }

                putchar('\n');

                /* on the first screen we reserve 2 extra lines for the title */
                if (i % break_lines == break_modulo) {
                        if (!press_any_key())
                                return 0;
                }
        }

        return 0;
}
Exemple #5
0
int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
        static const char status_indent[] = "         "; /* "[" STATUS "] " */
        _cleanup_free_ char *s = NULL;
        _cleanup_close_ int fd = -1;
        struct iovec iovec[6] = {};
        int n = 0;
        static bool prev_ephemeral;

        assert(format);

        /* This is independent of logging, as status messages are
         * optional and go exclusively to the console. */

        if (vasprintf(&s, format, ap) < 0)
                return log_oom();

        fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
        if (fd < 0)
                return fd;

        if (ellipse) {
                char *e;
                size_t emax, sl;
                int c;

                c = fd_columns(fd);
                if (c <= 0)
                        c = 80;

                sl = status ? sizeof(status_indent)-1 : 0;

                emax = c - sl - 1;
                if (emax < 3)
                        emax = 3;

                e = ellipsize(s, emax, 50);
                if (e) {
                        free(s);
                        s = e;
                }
        }

        if (prev_ephemeral)
                IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
        prev_ephemeral = ephemeral;

        if (status) {
                if (!isempty(status)) {
                        IOVEC_SET_STRING(iovec[n++], "[");
                        IOVEC_SET_STRING(iovec[n++], status);
                        IOVEC_SET_STRING(iovec[n++], "] ");
                } else
                        IOVEC_SET_STRING(iovec[n++], status_indent);
        }

        IOVEC_SET_STRING(iovec[n++], s);
        if (!ephemeral)
                IOVEC_SET_STRING(iovec[n++], "\n");

        if (writev(fd, iovec, n) < 0)
                return -errno;

        return 0;
}
static void display(Hashmap *a) {
        Iterator i;
        Group *g;
        Group **array;
        signed path_columns;
        unsigned rows, n = 0, j, maxtcpu = 0, maxtpath = 3; /* 3 for ellipsize() to work properly */
        char buffer[MAX3(21, FORMAT_BYTES_MAX, FORMAT_TIMESPAN_MAX)];

        assert(a);

        if (!terminal_is_dumb())
                fputs(ANSI_HOME_CLEAR, stdout);

        array = alloca(sizeof(Group*) * hashmap_size(a));

        HASHMAP_FOREACH(g, a, i)
                if (g->n_tasks_valid || g->cpu_valid || g->memory_valid || g->io_valid)
                        array[n++] = g;

        qsort_safe(array, n, sizeof(Group*), group_compare);

        /* Find the longest names in one run */
        for (j = 0; j < n; j++) {
                unsigned cputlen, pathtlen;

                format_timespan(buffer, sizeof(buffer), (usec_t) (array[j]->cpu_usage / NSEC_PER_USEC), 0);
                cputlen = strlen(buffer);
                maxtcpu = MAX(maxtcpu, cputlen);

                pathtlen = strlen(array[j]->path);
                maxtpath = MAX(maxtpath, pathtlen);
        }

        if (arg_cpu_type == CPU_PERCENT)
                xsprintf(buffer, "%6s", "%CPU");
        else
                xsprintf(buffer, "%*s", maxtcpu, "CPU Time");

        rows = lines();
        if (rows <= 10)
                rows = 10;

        if (on_tty()) {
                const char *on, *off;

                path_columns = columns() - 36 - strlen(buffer);
                if (path_columns < 10)
                        path_columns = 10;

                on = ansi_highlight_underline();
                off = ansi_underline();

                printf("%s%s%-*s%s %s%7s%s %s%s%s %s%8s%s %s%8s%s %s%8s%s%s\n",
                       ansi_underline(),
                       arg_order == ORDER_PATH ? on : "", path_columns, "Control Group",
                       arg_order == ORDER_PATH ? off : "",
                       arg_order == ORDER_TASKS ? on : "", arg_count == COUNT_PIDS ? "Tasks" : arg_count == COUNT_USERSPACE_PROCESSES ? "Procs" : "Proc+",
                       arg_order == ORDER_TASKS ? off : "",
                       arg_order == ORDER_CPU ? on : "", buffer,
                       arg_order == ORDER_CPU ? off : "",
                       arg_order == ORDER_MEMORY ? on : "", "Memory",
                       arg_order == ORDER_MEMORY ? off : "",
                       arg_order == ORDER_IO ? on : "", "Input/s",
                       arg_order == ORDER_IO ? off : "",
                       arg_order == ORDER_IO ? on : "", "Output/s",
                       arg_order == ORDER_IO ? off : "",
                       ansi_normal());
        } else
                path_columns = maxtpath;

        for (j = 0; j < n; j++) {
                _cleanup_free_ char *ellipsized = NULL;
                const char *path;

                if (on_tty() && j + 6 > rows)
                        break;

                g = array[j];

                path = isempty(g->path) ? "/" : g->path;
                ellipsized = ellipsize(path, path_columns, 33);
                printf("%-*s", path_columns, ellipsized ?: path);

                if (g->n_tasks_valid)
                        printf(" %7" PRIu64, g->n_tasks);
                else
                        fputs("       -", stdout);

                if (arg_cpu_type == CPU_PERCENT) {
                        if (g->cpu_valid)
                                printf(" %6.1f", g->cpu_fraction*100);
                        else
                                fputs("      -", stdout);
                } else
                        printf(" %*s", maxtcpu, format_timespan(buffer, sizeof(buffer), (usec_t) (g->cpu_usage / NSEC_PER_USEC), 0));

                printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->memory_valid, g->memory));
                printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->io_valid, g->io_input_bps));
                printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->io_valid, g->io_output_bps));

                putchar('\n');
        }
}
Exemple #7
0
static int display(Hashmap *a) {
        Iterator i;
        Group *g;
        Group **array;
        signed path_columns;
        unsigned rows, n = 0, j, maxtcpu = 0, maxtpath = 0;
        char buffer[MAX3(21, FORMAT_BYTES_MAX, FORMAT_TIMESPAN_MAX)];

        assert(a);

        /* Set cursor to top left corner and clear screen */
        if (on_tty())
                fputs("\033[H"
                      "\033[2J", stdout);

        array = alloca(sizeof(Group*) * hashmap_size(a));

        HASHMAP_FOREACH(g, a, i)
                if (g->n_tasks_valid || g->cpu_valid || g->memory_valid || g->io_valid)
                        array[n++] = g;

        qsort_safe(array, n, sizeof(Group*), group_compare);

        /* Find the longest names in one run */
        for (j = 0; j < n; j++) {
                unsigned cputlen, pathtlen;

                format_timespan(buffer, sizeof(buffer), (nsec_t) (array[j]->cpu_usage / NSEC_PER_USEC), 0);
                cputlen = strlen(buffer);
                maxtcpu = MAX(maxtcpu, cputlen);
                pathtlen = strlen(array[j]->path);
                maxtpath = MAX(maxtpath, pathtlen);
        }

        if (arg_cpu_type == CPU_PERCENT)
                snprintf(buffer, sizeof(buffer), "%6s", "%CPU");
        else
                snprintf(buffer, sizeof(buffer), "%*s", maxtcpu, "CPU Time");

        rows = lines();
        if (rows <= 10)
                rows = 10;

        if (on_tty()) {
                path_columns = columns() - 36 - strlen(buffer);
                if (path_columns < 10)
                        path_columns = 10;

                printf("%s%-*s%s %s%7s%s %s%s%s %s%8s%s %s%8s%s %s%8s%s\n\n",
                       arg_order == ORDER_PATH ? ON : "", path_columns, "Path",
                       arg_order == ORDER_PATH ? OFF : "",
                       arg_order == ORDER_TASKS ? ON : "", "Tasks",
                       arg_order == ORDER_TASKS ? OFF : "",
                       arg_order == ORDER_CPU ? ON : "", buffer,
                       arg_order == ORDER_CPU ? OFF : "",
                       arg_order == ORDER_MEMORY ? ON : "", "Memory",
                       arg_order == ORDER_MEMORY ? OFF : "",
                       arg_order == ORDER_IO ? ON : "", "Input/s",
                       arg_order == ORDER_IO ? OFF : "",
                       arg_order == ORDER_IO ? ON : "", "Output/s",
                       arg_order == ORDER_IO ? OFF : "");
        } else
                path_columns = maxtpath;

        for (j = 0; j < n; j++) {
                char *p;

                if (on_tty() && j + 5 > rows)
                        break;

                g = array[j];

                p = ellipsize(g->path, path_columns, 33);
                printf("%-*s", path_columns, p ? p : g->path);
                free(p);

                if (g->n_tasks_valid)
                        printf(" %7u", g->n_tasks);
                else
                        fputs("       -", stdout);

                if (arg_cpu_type == CPU_PERCENT) {
                        if (g->cpu_valid)
                                printf(" %6.1f", g->cpu_fraction*100);
                        else
                                fputs("      -", stdout);
                } else
                        printf(" %*s", maxtcpu, format_timespan(buffer, sizeof(buffer), (nsec_t) (g->cpu_usage / NSEC_PER_USEC), 0));

                if (g->memory_valid)
                        printf(" %8s", format_bytes(buffer, sizeof(buffer), g->memory));
                else
                        fputs("        -", stdout);

                if (g->io_valid) {
                        printf(" %8s",
                               format_bytes(buffer, sizeof(buffer), g->io_input_bps));
                        printf(" %8s",
                               format_bytes(buffer, sizeof(buffer), g->io_output_bps));
                } else
                        fputs("        -        -", stdout);

                putchar('\n');
        }

        return 0;
}
Exemple #8
0
char* optdoc(char* dst, size_t dst_size, const char* app_name, const option* options, size_t num_options, const char* loose_parameters)
{
	*dst = '\0';
	char* cur = dst;

	int w = snprintf(cur, dst_size, "%s [options] ", app_name);
	if (w == -1)
		return nullptr;
	cur += w;
	dst_size -= w;

	const option* oend = options + num_options;
	for (const option* o = options; o < oend; o++)
	{
		w = snprintf(cur, dst_size, "-%c%s%s ", o->abbrev, o->argname ? " " : "", o->argname ? o->argname : "");
		if (w == -1)
			return nullptr;
		cur += w;
		dst_size -= w;
	}

	if (loose_parameters && *loose_parameters)
	{
		w = snprintf(cur, dst_size, "%s", loose_parameters);
		cur += w;
		dst_size -= w;
	}

	w = snprintf(cur, dst_size, "\n\n");
	if (w == -1)
		return nullptr;
	cur += w;
	dst_size -= w;

	size_t max_len_fullname = 0;
	size_t max_len_arg_name = 0;
	for (const option* o = options; o < oend && dst_size > 0; o++)
	{
		max_len_fullname = __max(max_len_fullname, strlen(o->fullname ? o->fullname : ""));
		max_len_arg_name = __max(max_len_arg_name, strlen(o->argname ? o->argname : ""));
	}

	static const size_t MaxLen = 80;
	const size_t descStartCol = 3 + 1 + max_len_fullname + 5 + max_len_arg_name + 4;

	for (const option* o = options; o < oend && dst_size > 0; o++)
	{
		char fullname[64];
		*fullname = '\0';
		if (o->fullname)
			snprintf(fullname, " [--%s]", o->fullname);

		const char* odesc = o->desc ? o->desc : "";
		size_t newline = strcspn(odesc, oNEWLINE);
		char descline[128];
		if (newline > sizeof(descline))
			return nullptr;
		
		strlcpy(descline, odesc);
		bool do_more_lines = descline[newline] != '\0';
		descline[newline] = '\0';

		w = snprintf(cur, dst_size, "  -%c%- *s %- *s : %s\n"
			, o->abbrev
			, max_len_fullname + 5
			, fullname
			, max_len_arg_name
			, o->argname ? o->argname : ""
			, descline);
		if (w == -1)
			return nullptr;
		cur += w;
		dst_size -= w;

		while (do_more_lines)
		{
			odesc += newline + 1;
			newline = strcspn(odesc, oNEWLINE);
			if (newline > sizeof(descline))
				return nullptr;
		
			strlcpy(descline, odesc);
			do_more_lines = descline[newline] != '\0';
			descline[newline] = '\0';

			w = snprintf(cur, dst_size, "% *s%s\n"
				, descStartCol
				, " "
				, descline);
			if (w == -1)
				return dst;
			cur += w;
			dst_size -= w;
		}
	}

	ellipsize(dst, dst_size);
	return dst;
}
Exemple #9
0
static int show_sysfs_one(
                struct udev *udev,
                const char *seat,
                struct udev_list_entry **item,
                const char *sub,
                const char *prefix,
                unsigned n_columns) {

        assert(udev);
        assert(seat);
        assert(item);
        assert(prefix);

        while (*item) {
                struct udev_list_entry *next, *lookahead;
                struct udev_device *d;
                const char *sn, *name, *sysfs, *subsystem, *sysname;
                char *l, *k;
                bool is_master;

                sysfs = udev_list_entry_get_name(*item);
                if (!path_startswith(sysfs, sub))
                        return 0;

                d = udev_device_new_from_syspath(udev, sysfs);
                if (!d) {
                        *item = udev_list_entry_get_next(*item);
                        continue;
                }

                sn = udev_device_get_property_value(d, "ID_SEAT");
                if (isempty(sn))
                        sn = "seat0";

                /* Explicitly also check for tag 'seat' here */
                if (!streq(seat, sn) || !udev_device_has_tag(d, "seat")) {
                        udev_device_unref(d);
                        *item = udev_list_entry_get_next(*item);
                        continue;
                }

                is_master = udev_device_has_tag(d, "seat-master");

                name = udev_device_get_sysattr_value(d, "name");
                if (!name)
                        name = udev_device_get_sysattr_value(d, "id");
                subsystem = udev_device_get_subsystem(d);
                sysname = udev_device_get_sysname(d);

                /* Look if there's more coming after this */
                lookahead = next = udev_list_entry_get_next(*item);
                while (lookahead) {
                        const char *lookahead_sysfs;

                        lookahead_sysfs = udev_list_entry_get_name(lookahead);

                        if (path_startswith(lookahead_sysfs, sub) &&
                            !path_startswith(lookahead_sysfs, sysfs)) {
                                struct udev_device *lookahead_d;

                                lookahead_d = udev_device_new_from_syspath(udev, lookahead_sysfs);
                                if (lookahead_d) {
                                        const char *lookahead_sn;
                                        bool found;

                                        lookahead_sn = udev_device_get_property_value(d, "ID_SEAT");
                                        if (isempty(lookahead_sn))
                                                lookahead_sn = "seat0";

                                        found = streq(seat, lookahead_sn) && udev_device_has_tag(lookahead_d, "seat");
                                        udev_device_unref(lookahead_d);

                                        if (found)
                                                break;
                                }
                        }

                        lookahead = udev_list_entry_get_next(lookahead);
                }

                k = ellipsize(sysfs, n_columns, 20);
                printf("%s%s%s\n", prefix, draw_special_char(lookahead ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT),
                                   k ? k : sysfs);
                free(k);

                if (asprintf(&l,
                             "%s%s:%s%s%s%s",
                             is_master ? "[MASTER] " : "",
                             subsystem, sysname,
                             name ? " \"" : "", name ? name : "", name ? "\"" : "") < 0) {
                        udev_device_unref(d);
                        return -ENOMEM;
                }

                k = ellipsize(l, n_columns, 70);
                printf("%s%s%s\n", prefix, lookahead ? draw_special_char(DRAW_TREE_VERT) : "  ",
                                   k ? k : l);
                free(k);
                free(l);

                *item = next;
                if (*item) {
                        char *p;

                        p = strappend(prefix, lookahead ? draw_special_char(DRAW_TREE_VERT) : "  ");
                        show_sysfs_one(udev, seat, item, sysfs, p ? p : prefix, n_columns - 2);
                        free(p);
                }

                udev_device_unref(d);
        }

        return 0;
}
Exemple #10
0
static int print_inhibitors(DBusConnection *bus, DBusError *error) {
        DBusMessage *m, *reply;
        unsigned n = 0;
        DBusMessageIter iter, sub, sub2;
        int r;

        assert(bus);

        m = dbus_message_new_method_call(
                        "org.freedesktop.login1",
                        "/org/freedesktop/login1",
                        "org.freedesktop.login1.Manager",
                        "ListInhibitors");
        if (!m)
                return -ENOMEM;

        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
        if (!reply) {
                r = -EIO;
                goto finish;
        }

        if (!dbus_message_iter_init(reply, &iter)) {
                r = -ENOMEM;
                goto finish;
        }

        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
                r = -EIO;
                goto finish;
        }
        dbus_message_iter_recurse(&iter, &sub);

        printf("%-21s %-20s %-20s %-5s %6s %6s\n",
               "WHAT",
               "WHO",
               "WHY",
               "MODE",
               "UID",
               "PID");


        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
                const char *what, *who, *why, *mode;
                char *ewho, *ewhy;
                dbus_uint32_t uid, pid;

                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
                        r = -EIO;
                        goto finish;
                }

                dbus_message_iter_recurse(&sub, &sub2);

                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
                        r = -EIO;
                        goto finish;
                }

                ewho = ellipsize(who, 20, 66);
                ewhy = ellipsize(why, 20, 66);

                printf("%-21s %-20s %-20s %-5s %6lu %6lu\n",
                       what, ewho ? ewho : who, ewhy ? ewhy : why, mode, (unsigned long) uid, (unsigned long) pid);

                free(ewho);
                free(ewhy);

                dbus_message_iter_next(&sub);

                n++;
        }

        printf("\n%u inhibitors listed.\n", n);
        r = 0;

finish:
        if (m)
                dbus_message_unref(m);

        if (reply)
                dbus_message_unref(reply);

        return r;
}
Exemple #11
0
int status_vprintf(const char *status, ShowStatusFlags flags, const char *format, va_list ap) {
        static const char status_indent[] = "         "; /* "[" STATUS "] " */
        _cleanup_free_ char *s = NULL;
        _cleanup_close_ int fd = -1;
        struct iovec iovec[7] = {};
        int n = 0;
        static bool prev_ephemeral;

        assert(format);

        /* This is independent of logging, as status messages are
         * optional and go exclusively to the console. */

        if (vasprintf(&s, format, ap) < 0)
                return log_oom();

        /* Before you ask: yes, on purpose we open/close the console for each status line we write individually. This
         * is a good strategy to avoid PID 1 getting killed by the kernel's SAK concept (it doesn't fix this entirely,
         * but minimizes the time window the kernel might end up killing PID 1 due to SAK). It also makes things easier
         * for us so that we don't have to recover from hangups and suchlike triggered on the console. */

        fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
        if (fd < 0)
                return fd;

        if (FLAGS_SET(flags, SHOW_STATUS_ELLIPSIZE)) {
                char *e;
                size_t emax, sl;
                int c;

                c = fd_columns(fd);
                if (c <= 0)
                        c = 80;

                sl = status ? sizeof(status_indent)-1 : 0;

                emax = c - sl - 1;
                if (emax < 3)
                        emax = 3;

                e = ellipsize(s, emax, 50);
                if (e)
                        free_and_replace(s, e);
        }

        if (prev_ephemeral)
                iovec[n++] = IOVEC_MAKE_STRING(ANSI_REVERSE_LINEFEED "\r" ANSI_ERASE_TO_END_OF_LINE);

        if (status) {
                if (!isempty(status)) {
                        iovec[n++] = IOVEC_MAKE_STRING("[");
                        iovec[n++] = IOVEC_MAKE_STRING(status);
                        iovec[n++] = IOVEC_MAKE_STRING("] ");
                } else
                        iovec[n++] = IOVEC_MAKE_STRING(status_indent);
        }

        iovec[n++] = IOVEC_MAKE_STRING(s);
        iovec[n++] = IOVEC_MAKE_STRING("\n");

        if (prev_ephemeral && !FLAGS_SET(flags, SHOW_STATUS_EPHEMERAL))
                iovec[n++] = IOVEC_MAKE_STRING(ANSI_ERASE_TO_END_OF_LINE);
        prev_ephemeral = FLAGS_SET(flags, SHOW_STATUS_EPHEMERAL) ;

        if (writev(fd, iovec, n) < 0)
                return -errno;

        return 0;
}
static void test_one(const char *p) {
        _cleanup_free_ char *t;
        t = ellipsize(p, columns(), 70);
        puts(t);
}