tmux  3.2a
About: tmux is a terminal multiplexer that lets you switch easily between several programs in one terminal.
  Fossies Dox: tmux-3.2a.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

window-buffer.c
Go to the documentation of this file.
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 #include <unistd.h>
26 
27 #include "tmux.h"
28 
29 static struct screen *window_buffer_init(struct window_mode_entry *,
30  struct cmd_find_state *, struct args *);
31 static void window_buffer_free(struct window_mode_entry *);
32 static void window_buffer_resize(struct window_mode_entry *, u_int,
33  u_int);
34 static void window_buffer_update(struct window_mode_entry *);
35 static void window_buffer_key(struct window_mode_entry *,
36  struct client *, struct session *,
37  struct winlink *, key_code, struct mouse_event *);
38 
39 #define WINDOW_BUFFER_DEFAULT_COMMAND "paste-buffer -b '%%'"
40 
41 #define WINDOW_BUFFER_DEFAULT_FORMAT \
42  "#{t/p:buffer_created}: #{buffer_sample}"
43 
44 #define WINDOW_BUFFER_DEFAULT_KEY_FORMAT \
45  "#{?#{e|<:#{line},10}," \
46  "#{line}" \
47  "," \
48  "#{?#{e|<:#{line},36}," \
49  "M-#{a:#{e|+:97,#{e|-:#{line},10}}}" \
50  "," \
51  "" \
52  "}" \
53  "}"
54 
55 static const struct menu_item window_buffer_menu_items[] = {
56  { "Paste", 'p', NULL },
57  { "Paste Tagged", 'P', NULL },
58  { "", KEYC_NONE, NULL },
59  { "Tag", 't', NULL },
60  { "Tag All", '\024', NULL },
61  { "Tag None", 'T', NULL },
62  { "", KEYC_NONE, NULL },
63  { "Delete", 'd', NULL },
64  { "Delete Tagged", 'D', NULL },
65  { "", KEYC_NONE, NULL },
66  { "Cancel", 'q', NULL },
67 
68  { NULL, KEYC_NONE, NULL }
69 };
70 
71 const struct window_mode window_buffer_mode = {
72  .name = "buffer-mode",
73  .default_format = WINDOW_BUFFER_DEFAULT_FORMAT,
74 
75  .init = window_buffer_init,
76  .free = window_buffer_free,
77  .resize = window_buffer_resize,
78  .update = window_buffer_update,
79  .key = window_buffer_key,
80 };
81 
86 };
87 static const char *window_buffer_sort_list[] = {
88  "time",
89  "name",
90  "size"
91 };
93 
95  const char *name;
96  u_int order;
97  size_t size;
98 };
99 
101  struct window_pane *wp;
102  struct cmd_find_state fs;
103 
105  char *command;
106  char *format;
107  char *key_format;
108 
110  u_int item_size;
111 };
112 
114  u_int wp_id;
115  char *name;
116  struct paste_buffer *pb;
117 };
118 
119 static struct window_buffer_itemdata *
121 {
122  struct window_buffer_itemdata *item;
123 
124  data->item_list = xreallocarray(data->item_list, data->item_size + 1,
125  sizeof *data->item_list);
126  item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item);
127  return (item);
128 }
129 
130 static void
132 {
133  free((void *)item->name);
134  free(item);
135 }
136 
137 static int
138 window_buffer_cmp(const void *a0, const void *b0)
139 {
140  const struct window_buffer_itemdata *const *a = a0;
141  const struct window_buffer_itemdata *const *b = b0;
142  int result = 0;
143 
145  result = (*b)->order - (*a)->order;
147  result = (*b)->size - (*a)->size;
148 
149  /* Use WINDOW_BUFFER_BY_NAME as default order and tie breaker. */
150  if (result == 0)
151  result = strcmp((*a)->name, (*b)->name);
152 
154  result = -result;
155  return (result);
156 }
157 
158 static void
159 window_buffer_build(void *modedata, struct mode_tree_sort_criteria *sort_crit,
160  __unused uint64_t *tag, const char *filter)
161 {
162  struct window_buffer_modedata *data = modedata;
163  struct window_buffer_itemdata *item;
164  u_int i;
165  struct paste_buffer *pb;
166  char *text, *cp;
167  struct format_tree *ft;
168  struct session *s = NULL;
169  struct winlink *wl = NULL;
170  struct window_pane *wp = NULL;
171 
172  for (i = 0; i < data->item_size; i++)
174  free(data->item_list);
175  data->item_list = NULL;
176  data->item_size = 0;
177 
178  pb = NULL;
179  while ((pb = paste_walk(pb)) != NULL) {
180  item = window_buffer_add_item(data);
181  item->name = xstrdup(paste_buffer_name(pb));
182  paste_buffer_data(pb, &item->size);
183  item->order = paste_buffer_order(pb);
184  }
185 
186  window_buffer_sort = sort_crit;
187  qsort(data->item_list, data->item_size, sizeof *data->item_list,
189 
190  if (cmd_find_valid_state(&data->fs)) {
191  s = data->fs.s;
192  wl = data->fs.wl;
193  wp = data->fs.wp;
194  }
195 
196  for (i = 0; i < data->item_size; i++) {
197  item = data->item_list[i];
198 
199  pb = paste_get_name(item->name);
200  if (pb == NULL)
201  continue;
202  ft = format_create(NULL, NULL, FORMAT_NONE, 0);
203  format_defaults(ft, NULL, s, wl, wp);
205 
206  if (filter != NULL) {
207  cp = format_expand(ft, filter);
208  if (!format_true(cp)) {
209  free(cp);
210  format_free(ft);
211  continue;
212  }
213  free(cp);
214  }
215 
216  text = format_expand(ft, data->format);
217  mode_tree_add(data->data, NULL, item, item->order, item->name,
218  text, -1);
219  free(text);
220 
221  format_free(ft);
222  }
223 
224 }
225 
226 static void
227 window_buffer_draw(__unused void *modedata, void *itemdata,
228  struct screen_write_ctx *ctx, u_int sx, u_int sy)
229 {
230  struct window_buffer_itemdata *item = itemdata;
231  struct paste_buffer *pb;
232  const char *pdata, *start, *end;
233  char *buf = NULL;
234  size_t psize;
235  u_int i, cx = ctx->s->cx, cy = ctx->s->cy;
236 
237  pb = paste_get_name(item->name);
238  if (pb == NULL)
239  return;
240 
241  pdata = end = paste_buffer_data(pb, &psize);
242  for (i = 0; i < sy; i++) {
243  start = end;
244  while (end != pdata + psize && *end != '\n')
245  end++;
246  buf = xreallocarray(buf, 4, end - start + 1);
247  utf8_strvis(buf, start, end - start,
248  VIS_OCTAL|VIS_CSTYLE|VIS_TAB);
249  if (*buf != '\0') {
250  screen_write_cursormove(ctx, cx, cy + i, 0);
251  screen_write_nputs(ctx, sx, &grid_default_cell, "%s",
252  buf);
253  }
254 
255  if (end == pdata + psize)
256  break;
257  end++;
258  }
259  free(buf);
260 }
261 
262 static int
263 window_buffer_search(__unused void *modedata, void *itemdata, const char *ss)
264 {
265  struct window_buffer_itemdata *item = itemdata;
266  struct paste_buffer *pb;
267  const char *bufdata;
268  size_t bufsize;
269 
270  if ((pb = paste_get_name(item->name)) == NULL)
271  return (0);
272  if (strstr(item->name, ss) != NULL)
273  return (1);
274  bufdata = paste_buffer_data(pb, &bufsize);
275  return (memmem(bufdata, bufsize, ss, strlen(ss)) != NULL);
276 }
277 
278 static void
279 window_buffer_menu(void *modedata, struct client *c, key_code key)
280 {
281  struct window_buffer_modedata *data = modedata;
282  struct window_pane *wp = data->wp;
283  struct window_mode_entry *wme;
284 
285  wme = TAILQ_FIRST(&wp->modes);
286  if (wme == NULL || wme->data != modedata)
287  return;
288  window_buffer_key(wme, c, NULL, NULL, key, NULL);
289 }
290 
291 static key_code
292 window_buffer_get_key(void *modedata, void *itemdata, u_int line)
293 {
294  struct window_buffer_modedata *data = modedata;
295  struct window_buffer_itemdata *item = itemdata;
296  struct format_tree *ft;
297  struct session *s = NULL;
298  struct winlink *wl = NULL;
299  struct window_pane *wp = NULL;
300  struct paste_buffer *pb;
301  char *expanded;
302  key_code key;
303 
304  if (cmd_find_valid_state(&data->fs)) {
305  s = data->fs.s;
306  wl = data->fs.wl;
307  wp = data->fs.wp;
308  }
309  pb = paste_get_name(item->name);
310  if (pb == NULL)
311  return KEYC_NONE;
312 
313  ft = format_create(NULL, NULL, FORMAT_NONE, 0);
314  format_defaults(ft, NULL, NULL, 0, NULL);
315  format_defaults(ft, NULL, s, wl, wp);
317  format_add(ft, "line", "%u", line);
318 
319  expanded = format_expand(ft, data->key_format);
320  key = key_string_lookup_string(expanded);
321  free(expanded);
322  format_free(ft);
323  return key;
324 }
325 
326 static struct screen *
328  struct args *args)
329 {
330  struct window_pane *wp = wme->wp;
332  struct screen *s;
333 
334  wme->data = data = xcalloc(1, sizeof *data);
335  data->wp = wp;
336  cmd_find_copy_state(&data->fs, fs);
337 
338  if (args == NULL || !args_has(args, 'F'))
340  else
341  data->format = xstrdup(args_get(args, 'F'));
342  if (args == NULL || !args_has(args, 'K'))
344  else
345  data->key_format = xstrdup(args_get(args, 'K'));
346  if (args == NULL || args->argc == 0)
348  else
349  data->command = xstrdup(args->argv[0]);
350 
355  mode_tree_zoom(data->data, args);
356 
357  mode_tree_build(data->data);
358  mode_tree_draw(data->data);
359 
360  return (s);
361 }
362 
363 static void
365 {
366  struct window_buffer_modedata *data = wme->data;
367  u_int i;
368 
369  if (data == NULL)
370  return;
371 
372  mode_tree_free(data->data);
373 
374  for (i = 0; i < data->item_size; i++)
375  window_buffer_free_item(data->item_list[i]);
376  free(data->item_list);
377 
378  free(data->format);
379  free(data->key_format);
380  free(data->command);
381 
382  free(data);
383 }
384 
385 static void
386 window_buffer_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
387 {
388  struct window_buffer_modedata *data = wme->data;
389 
390  mode_tree_resize(data->data, sx, sy);
391 }
392 
393 static void
395 {
396  struct window_buffer_modedata *data = wme->data;
397 
398  mode_tree_build(data->data);
399  mode_tree_draw(data->data);
400  data->wp->flags |= PANE_REDRAW;
401 }
402 
403 static void
404 window_buffer_do_delete(void *modedata, void *itemdata,
405  __unused struct client *c, __unused key_code key)
406 {
407  struct window_buffer_modedata *data = modedata;
408  struct window_buffer_itemdata *item = itemdata;
409  struct paste_buffer *pb;
410 
411  if (item == mode_tree_get_current(data->data))
412  mode_tree_down(data->data, 0);
413  if ((pb = paste_get_name(item->name)) != NULL)
414  paste_free(pb);
415 }
416 
417 static void
418 window_buffer_do_paste(void *modedata, void *itemdata, struct client *c,
420 {
421  struct window_buffer_modedata *data = modedata;
422  struct window_buffer_itemdata *item = itemdata;
423 
424  if (paste_get_name(item->name) != NULL)
425  mode_tree_run_command(c, NULL, data->command, item->name);
426 }
427 
428 static void
430 {
431  free(ed->name);
432  free(ed);
433 }
434 
435 static void
436 window_buffer_edit_close_cb(char *buf, size_t len, void *arg)
437 {
438  struct window_buffer_editdata *ed = arg;
439  size_t oldlen;
440  const char *oldbuf;
441  struct paste_buffer *pb;
442  struct window_pane *wp;
444  struct window_mode_entry *wme;
445 
446  if (buf == NULL || len == 0) {
448  return;
449  }
450 
451  pb = paste_get_name(ed->name);
452  if (pb == NULL || pb != ed->pb) {
454  return;
455  }
456 
457  oldbuf = paste_buffer_data(pb, &oldlen);
458  if (oldlen != '\0' &&
459  oldbuf[oldlen - 1] != '\n' &&
460  buf[len - 1] == '\n')
461  len--;
462  if (len != 0)
463  paste_replace(pb, buf, len);
464 
466  if (wp != NULL) {
467  wme = TAILQ_FIRST(&wp->modes);
468  if (wme->mode == &window_buffer_mode) {
469  data = wme->data;
470  mode_tree_build(data->data);
471  mode_tree_draw(data->data);
472  }
473  wp->flags |= PANE_REDRAW;
474  }
476 }
477 
478 static void
480  struct window_buffer_itemdata *item, struct client *c)
481 {
482  struct paste_buffer *pb;
483  const char *buf;
484  size_t len;
485  struct window_buffer_editdata *ed;
486 
487  if ((pb = paste_get_name(item->name)) == NULL)
488  return;
489  buf = paste_buffer_data(pb, &len);
490 
491  ed = xcalloc(1, sizeof *ed);
492  ed->wp_id = data->wp->id;
494  ed->pb = pb;
495 
496  if (popup_editor(c, buf, len, window_buffer_edit_close_cb, ed) != 0)
498 }
499 
500 static void
502  __unused struct session *s, __unused struct winlink *wl, key_code key,
503  struct mouse_event *m)
504 {
505  struct window_pane *wp = wme->wp;
506  struct window_buffer_modedata *data = wme->data;
507  struct mode_tree_data *mtd = data->data;
508  struct window_buffer_itemdata *item;
509  int finished;
510 
511  finished = mode_tree_key(mtd, c, &key, m, NULL, NULL);
512  switch (key) {
513  case 'e':
514  item = mode_tree_get_current(mtd);
515  window_buffer_start_edit(data, item, c);
516  break;
517  case 'd':
518  item = mode_tree_get_current(mtd);
519  window_buffer_do_delete(data, item, c, key);
520  mode_tree_build(mtd);
521  break;
522  case 'D':
524  mode_tree_build(mtd);
525  break;
526  case 'P':
528  finished = 1;
529  break;
530  case 'p':
531  case '\r':
532  item = mode_tree_get_current(mtd);
533  window_buffer_do_paste(data, item, c, key);
534  finished = 1;
535  break;
536  }
537  if (finished || paste_get_top(NULL) == NULL)
539  else {
540  mode_tree_draw(mtd);
541  wp->flags |= PANE_REDRAW;
542  }
543 }
int args_has(struct args *args, u_char flag)
Definition: arguments.c:259
const char * args_get(struct args *args, u_char flag)
Definition: arguments.c:295
void cmd_find_copy_state(struct cmd_find_state *dst, struct cmd_find_state *src)
Definition: cmd-find.c:689
int cmd_find_valid_state(struct cmd_find_state *fs)
Definition: cmd-find.c:664
#define __unused
Definition: compat.h:60
void * memmem(const void *, size_t, const void *, size_t)
void format_defaults(struct format_tree *ft, struct client *c, struct session *s, struct winlink *wl, struct window_pane *wp)
Definition: format.c:4684
void format_add(struct format_tree *ft, const char *key, const char *fmt,...)
Definition: format.c:3126
struct format_tree * format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
Definition: format.c:3042
char * format_expand(struct format_tree *ft, const char *fmt)
Definition: format.c:4609
void format_free(struct format_tree *ft)
Definition: format.c:3066
void format_defaults_paste_buffer(struct format_tree *ft, struct paste_buffer *pb)
Definition: format.c:4788
int format_true(const char *s)
Definition: format.c:3471
const struct grid_cell grid_default_cell
Definition: grid.c:39
key_code key_string_lookup_string(const char *string)
Definition: key-string.c:165
key_code key
Definition: key-string.c:32
void mode_tree_down(struct mode_tree_data *mtd, int wrap)
Definition: mode-tree.c:260
void mode_tree_build(struct mode_tree_data *mtd)
Definition: mode-tree.c:477
void mode_tree_free(struct mode_tree_data *mtd)
Definition: mode-tree.c:521
struct mode_tree_data * mode_tree_start(struct window_pane *wp, struct args *args, mode_tree_build_cb buildcb, mode_tree_draw_cb drawcb, mode_tree_search_cb searchcb, mode_tree_menu_cb menucb, mode_tree_height_cb heightcb, mode_tree_key_cb keycb, void *modedata, const struct menu_item *menu, const char **sort_list, u_int sort_size, struct screen **s)
Definition: mode-tree.c:389
void mode_tree_zoom(struct mode_tree_data *mtd, struct args *args)
Definition: mode-tree.c:443
struct mode_tree_item * mode_tree_add(struct mode_tree_data *mtd, struct mode_tree_item *parent, void *itemdata, uint64_t tag, const char *name, const char *text, int expanded)
Definition: mode-tree.c:553
void mode_tree_run_command(struct client *c, struct cmd_find_state *fs, const char *template, const char *name)
Definition: mode-tree.c:1193
int mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, struct mouse_event *m, u_int *xp, u_int *yp)
Definition: mode-tree.c:977
void * mode_tree_get_current(struct mode_tree_data *mtd)
Definition: mode-tree.c:275
void mode_tree_each_tagged(struct mode_tree_data *mtd, mode_tree_each_cb cb, struct client *c, key_code key, int current)
Definition: mode-tree.c:367
void mode_tree_resize(struct mode_tree_data *mtd, u_int sx, u_int sy)
Definition: mode-tree.c:540
void mode_tree_draw(struct mode_tree_data *mtd)
Definition: mode-tree.c:616
#define nitems(_a)
const char * paste_buffer_name(struct paste_buffer *pb)
Definition: paste.c:77
struct paste_buffer * paste_get_name(const char *name)
Definition: paste.c:130
struct paste_buffer * paste_get_top(const char **name)
Definition: paste.c:116
u_int paste_buffer_order(struct paste_buffer *pb)
Definition: paste.c:84
void paste_replace(struct paste_buffer *pb, char *data, size_t size)
Definition: paste.c:301
struct paste_buffer * paste_walk(struct paste_buffer *pb)
Definition: paste.c:107
void paste_free(struct paste_buffer *pb)
Definition: paste.c:143
const char * paste_buffer_data(struct paste_buffer *pb, size_t *size)
Definition: paste.c:98
int popup_editor(struct client *c, const char *buf, size_t len, popup_finish_edit_cb cb, void *arg)
Definition: popup.c:403
void screen_write_cursormove(struct screen_write_ctx *ctx, int px, int py, int origin)
void screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen, const struct grid_cell *gcp, const char *fmt,...)
Definition: screen-write.c:476
Definition: tmux.h:1435
int argc
Definition: tmux.h:1437
char ** argv
Definition: tmux.h:1438
Definition: tmux.h:1608
struct window_pane * wp
Definition: tmux.h:1454
struct session * s
Definition: tmux.h:1451
struct winlink * wl
Definition: tmux.h:1452
struct window_pane * wp
Definition: mode-tree.c:36
char * data
Definition: paste.c:33
struct screen * s
Definition: tmux.h:851
Definition: tmux.h:816
u_int cy
Definition: tmux.h:824
u_int cx
Definition: tmux.h:823
Definition: tmux.h:1179
struct paste_buffer * pb
struct cmd_find_state fs
struct window_buffer_itemdata ** item_list
struct window_pane * wp
struct mode_tree_data * data
Definition: tmux.h:927
const struct window_mode * mode
Definition: tmux.h:931
void * data
Definition: tmux.h:932
struct window_pane * wp
Definition: tmux.h:928
const char * name
Definition: tmux.h:906
int flags
Definition: tmux.h:977
u_int sy
Definition: tmux.h:969
u_int sx
Definition: tmux.h:968
u_int id
Definition: tmux.h:959
struct window_pane * window_pane_find_by_id(u_int)
Definition: window.c:841
unsigned long long key_code
Definition: tmux.h:177
#define KEYC_NONE
Definition: tmux.h:113
#define FORMAT_NONE
Definition: tmux.h:1973
#define PANE_REDRAW
Definition: tmux.h:978
int utf8_strvis(char *, const char *, size_t, int)
Definition: utf8.c:314
void window_pane_reset_mode(struct window_pane *)
Definition: window.c:1105
static void window_buffer_update(struct window_mode_entry *)
static void window_buffer_do_delete(void *modedata, void *itemdata, struct client *c, key_code key)
static const char * window_buffer_sort_list[]
Definition: window-buffer.c:87
static void window_buffer_build(void *modedata, struct mode_tree_sort_criteria *sort_crit, uint64_t *tag, const char *filter)
#define WINDOW_BUFFER_DEFAULT_KEY_FORMAT
Definition: window-buffer.c:44
static void window_buffer_start_edit(struct window_buffer_modedata *data, struct window_buffer_itemdata *item, struct client *c)
static struct window_buffer_itemdata * window_buffer_add_item(struct window_buffer_modedata *data)
static struct screen * window_buffer_init(struct window_mode_entry *, struct cmd_find_state *, struct args *)
static void window_buffer_menu(void *modedata, struct client *c, key_code key)
#define WINDOW_BUFFER_DEFAULT_COMMAND
Definition: window-buffer.c:39
static void window_buffer_free(struct window_mode_entry *)
#define WINDOW_BUFFER_DEFAULT_FORMAT
Definition: window-buffer.c:41
static int window_buffer_cmp(const void *a0, const void *b0)
static void window_buffer_do_paste(void *modedata, void *itemdata, struct client *c, key_code key)
static struct mode_tree_sort_criteria * window_buffer_sort
Definition: window-buffer.c:92
static key_code window_buffer_get_key(void *modedata, void *itemdata, u_int line)
static void window_buffer_free_item(struct window_buffer_itemdata *item)
static const struct menu_item window_buffer_menu_items[]
Definition: window-buffer.c:55
window_buffer_sort_type
Definition: window-buffer.c:82
@ WINDOW_BUFFER_BY_TIME
Definition: window-buffer.c:83
@ WINDOW_BUFFER_BY_NAME
Definition: window-buffer.c:84
@ WINDOW_BUFFER_BY_SIZE
Definition: window-buffer.c:85
static void window_buffer_draw(void *modedata, void *itemdata, struct screen_write_ctx *ctx, u_int sx, u_int sy)
static void window_buffer_resize(struct window_mode_entry *, u_int, u_int)
static int window_buffer_search(void *modedata, void *itemdata, const char *ss)
static void window_buffer_finish_edit(struct window_buffer_editdata *ed)
static void window_buffer_key(struct window_mode_entry *, struct client *, struct session *, struct winlink *, key_code, struct mouse_event *)
static void window_buffer_edit_close_cb(char *buf, size_t len, void *arg)
const struct window_mode window_buffer_mode
Definition: window-buffer.c:71
void * xreallocarray(void *ptr, size_t nmemb, size_t size)
Definition: xmalloc.c:61
void * xcalloc(size_t nmemb, size_t size)
Definition: xmalloc.c:41
char * xstrdup(const char *str)
Definition: xmalloc.c:89