pacemaker  2.0.2-debe490
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
output_text.c
Go to the documentation of this file.
1 /*
2  * Copyright 2019 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <stdlib.h>
11 #include <crm/crm.h>
12 #include <crm/common/output.h>
13 
14 /* Disabled for the moment, but we can enable it (or remove it entirely)
15  * when we make a decision on whether this is preferred output.
16  */
17 #define FANCY_TEXT_OUTPUT 0
18 
19 typedef struct text_list_data_s {
20  unsigned int len;
21  char *singular_noun;
22  char *plural_noun;
24 
25 typedef struct text_private_s {
26  GQueue *parent_q;
28 
29 static void
30 text_free_priv(pcmk__output_t *out) {
31  text_private_t *priv = out->priv;
32 
33  if (priv == NULL) {
34  return;
35  }
36 
37  g_queue_free(priv->parent_q);
38  free(priv);
39 }
40 
41 static bool
42 text_init(pcmk__output_t *out) {
43  text_private_t *priv = NULL;
44 
45  /* If text_init was previously called on this output struct, just return. */
46  if (out->priv != NULL) {
47  return true;
48  } else {
49  out->priv = calloc(1, sizeof(text_private_t));
50  if (out->priv == NULL) {
51  return false;
52  }
53 
54  priv = out->priv;
55  }
56 
57  priv->parent_q = g_queue_new();
58  return true;
59 }
60 
61 static void
62 text_finish(pcmk__output_t *out, crm_exit_t exit_status) {
63  /* This function intentionally left blank */
64 }
65 
66 static void
67 text_reset(pcmk__output_t *out) {
68  CRM_ASSERT(out->priv != NULL);
69 
70  text_free_priv(out);
71  text_init(out);
72 }
73 
74 static void
75 text_subprocess_output(pcmk__output_t *out, int exit_status,
76  const char *proc_stdout, const char *proc_stderr) {
77  if (proc_stdout != NULL) {
78  fprintf(out->dest, "%s\n", proc_stdout);
79  }
80 
81  if (proc_stderr != NULL) {
82  fprintf(out->dest, "%s\n", proc_stderr);
83  }
84 }
85 
86 G_GNUC_PRINTF(2, 3)
87 static void
88 text_info(pcmk__output_t *out, const char *format, ...) {
89  va_list ap;
90  int len = 0;
91 
92  va_start(ap, format);
93 
94  /* Informational output does not get indented, to separate it from other
95  * potentially indented list output.
96  */
97  len = vfprintf(out->dest, format, ap);
98  CRM_ASSERT(len > 0);
99  va_end(ap);
100 
101  /* Add a newline. */
102  fprintf(out->dest, "\n");
103 }
104 
105 static void
106 text_output_xml(pcmk__output_t *out, const char *name, const char *buf) {
107  text_private_t *priv = out->priv;
108 
109  CRM_ASSERT(priv != NULL);
110  pcmk__indented_printf(out, "%s", buf);
111 }
112 
113 static void
114 text_begin_list(pcmk__output_t *out, const char *name, const char *singular_noun,
115  const char *plural_noun) {
116  text_private_t *priv = out->priv;
117  text_list_data_t *new_list = NULL;
118 
119  CRM_ASSERT(priv != NULL);
120 
121 #if FANCY_TEXT_OUTPUT > 0
122  pcmk__indented_printf(out, "%s:\n", name);
123 #endif
124 
125  new_list = calloc(1, sizeof(text_list_data_t));
126  new_list->len = 0;
127  new_list->singular_noun = singular_noun == NULL ? NULL : strdup(singular_noun);
128  new_list->plural_noun = plural_noun == NULL ? NULL : strdup(plural_noun);
129 
130  g_queue_push_tail(priv->parent_q, new_list);
131 }
132 
133 static void
134 text_list_item(pcmk__output_t *out, const char *id, const char *content) {
135  text_private_t *priv = out->priv;
136 
137  CRM_ASSERT(priv != NULL);
138 
139 #if FANCY_TEXT_OUTPUT > 0
140  if (id != NULL) {
141  pcmk__indented_printf(out, "* %s: %s\n", id, content);
142  } else {
143  pcmk__indented_printf(out, "* %s\n", content);
144  }
145 #else
146  fprintf(out->dest, "%s\n", content);
147 #endif
148 
149  ((text_list_data_t *) g_queue_peek_tail(priv->parent_q))->len++;
150 }
151 
152 static void
153 text_end_list(pcmk__output_t *out) {
154  text_private_t *priv = out->priv;
155  text_list_data_t *node = NULL;
156 
157  CRM_ASSERT(priv != NULL);
158  node = g_queue_pop_tail(priv->parent_q);
159 
160  if (node->singular_noun != NULL && node->plural_noun != NULL) {
161  if (node->len == 1) {
162  pcmk__indented_printf(out, "%d %s found\n", node->len, node->singular_noun);
163  } else {
164  pcmk__indented_printf(out, "%d %s found\n", node->len, node->plural_noun);
165  }
166  }
167 
168  free(node);
169 }
170 
172 pcmk__mk_text_output(char **argv) {
173  pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t));
174 
175  if (retval == NULL) {
176  return NULL;
177  }
178 
179  retval->request = g_strjoinv(" ", argv);
180  retval->supports_quiet = true;
181 
182  retval->init = text_init;
183  retval->free_priv = text_free_priv;
184  retval->finish = text_finish;
185  retval->reset = text_reset;
186 
188  retval->message = pcmk__call_message;
189 
190  retval->subprocess_output = text_subprocess_output;
191  retval->info = text_info;
192  retval->output_xml = text_output_xml;
193 
194  retval->begin_list = text_begin_list;
195  retval->list_item = text_list_item;
196  retval->end_list = text_end_list;
197 
198  return retval;
199 }
200 
201 G_GNUC_PRINTF(2, 3)
202 void
203 pcmk__indented_printf(pcmk__output_t *out, const char *format, ...) {
204  va_list ap;
205  int len = 0;
206 #if FANCY_TEXT_OUTPUT > 0
207  int level = 0;
208  text_private_t *priv = out->priv;
209 
210  CRM_ASSERT(priv != NULL);
211 
212  level = g_queue_get_length(priv->parent_q);
213 
214  for (int i = 0; i < level; i++) {
215  putc('\t', out->dest);
216  }
217 #endif
218 
219  va_start(ap, format);
220  len = vfprintf(out->dest, format, ap);
221  CRM_ASSERT(len > 0);
222  va_end(ap);
223 }
void(* finish)(pcmk__output_t *out, crm_exit_t exit_status)
Definition: output.h:214
bool(* init)(pcmk__output_t *out)
Definition: output.h:186
pcmk__output_t * pcmk__mk_text_output(char **argv)
Definition: output_text.c:172
A dumping ground.
Formatted output for pacemaker tools.
void(*) void(* output_xml)(pcmk__output_t *out, const char *name, const char *buf)
Definition: output.h:298
void(* register_message)(pcmk__output_t *out, const char *message_id, pcmk__message_fn_t fn)
Definition: output.h:244
void(* reset)(pcmk__output_t *out)
Definition: output.h:231
bool supports_quiet
Does this formatter support a special quiet mode?
Definition: output.h:145
int(* message)(pcmk__output_t *out, const char *message_id,...)
Definition: output.h:262
enum crm_exit_e crm_exit_t
void(* list_item)(pcmk__output_t *out, const char *name, const char *content)
Definition: output.h:329
void * priv
Implementation-specific private data.
Definition: output.h:170
int pcmk__call_message(pcmk__output_t *out, const char *message_id,...)
Definition: output.c:117
char * request
A copy of the request that generated this output.
Definition: output.h:136
void(* end_list)(pcmk__output_t *out)
Definition: output.h:341
void(* begin_list)(pcmk__output_t *out, const char *name, const char *singular_noun, const char *plural_noun)
Definition: output.h:318
void(* subprocess_output)(pcmk__output_t *out, int exit_status, const char *proc_stdout, const char *proc_stderr)
Definition: output.h:273
struct text_private_s text_private_t
FILE * dest
Where output should be written.
Definition: output.h:153
void(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
Definition: output.h:288
#define CRM_ASSERT(expr)
Definition: results.h:42
void(* free_priv)(pcmk__output_t *out)
Definition: output.h:197
void pcmk__indented_printf(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
This structure contains everything that makes up a single output formatter.
Definition: output.h:124
struct text_list_data_s text_list_data_t
void pcmk__register_message(pcmk__output_t *out, const char *message_id, pcmk__message_fn_t fn)
Definition: output.c:135