FreeRDP
generate_argument_manpage.c
1 #include <stdlib.h>
2 #include <stdbool.h>
3 #include <stdio.h>
4 #include <ctype.h>
5 #include <string.h>
6 
7 #include "../cmdline.h"
8 
9 static char* resize(char** buffer, size_t* size, size_t increment)
10 {
11  const size_t nsize = *size + increment;
12  char* tmp = realloc(*buffer, nsize);
13  if (!tmp)
14  {
15  (void)fprintf(stderr,
16  "Could not reallocate string buffer from %" PRIuz " to %" PRIuz " bytes.\n",
17  *size, nsize);
18  free(*buffer);
19  return NULL;
20  }
21  memset(&tmp[*size], '\0', increment);
22  *size = nsize;
23  *buffer = tmp;
24  return tmp;
25 }
26 
27 static char* append(char** buffer, size_t* size, const char* str)
28 {
29  const size_t len = strnlen(*buffer, *size);
30  const size_t add = strlen(str);
31  const size_t required = len + add + 1;
32 
33  if (required > *size)
34  {
35  if (!resize(buffer, size, required - *size))
36  return NULL;
37  }
38  strncpy(&(*buffer)[len], str, add);
39  return *buffer;
40 }
41 
42 static LPSTR tr_esc_str(LPCSTR arg, bool format)
43 {
44  const char* str = NULL;
45  LPSTR tmp = NULL;
46  size_t ds = 0;
47 
48  if (NULL == arg)
49  return NULL;
50 
51  const size_t s = strlen(arg) + 1;
52  if (!resize(&tmp, &ds, s))
53  exit(-2);
54 
55  for (size_t x = 0; x < s; x++)
56  {
57  char data[2] = { 0 };
58  switch (arg[x])
59  {
60  case '-':
61  str = "\\-";
62  if (!append(&tmp, &ds, str))
63  exit(-3);
64  break;
65 
66  case '<':
67  if (format)
68  str = "\\fI";
69  else
70  str = "<";
71 
72  if (!append(&tmp, &ds, str))
73  exit(-3);
74  break;
75 
76  case '>':
77  if (format)
78  str = "\\fR";
79  else
80  str = ">";
81 
82  if (!append(&tmp, &ds, str))
83  exit(-4);
84  break;
85 
86  case '\'':
87  str = "\\*(Aq";
88  if (!append(&tmp, &ds, str))
89  exit(-4);
90  break;
91 
92  case '.':
93  if (!append(&tmp, &ds, "\\&."))
94  exit(-6);
95  break;
96 
97  case '\r':
98  case '\n':
99  if (!append(&tmp, &ds, "\n.br\n"))
100  exit(-7);
101  break;
102 
103  default:
104  data[0] = arg[x];
105  if (!append(&tmp, &ds, data))
106  exit(-8);
107  break;
108  }
109  }
110 
111  return tmp;
112 }
113 
114 int main(int argc, char* argv[])
115 {
116  size_t elements = sizeof(global_cmd_args) / sizeof(global_cmd_args[0]);
117 
118  if (argc != 2)
119  {
120  (void)fprintf(stderr, "Usage: %s <output file name>\n", argv[0]);
121  return -1;
122  }
123 
124  const char* fname = argv[1];
125 
126  (void)fprintf(stdout, "Generating manpage file '%s'\n", fname);
127  FILE* fp = fopen(fname, "w");
128  if (NULL == fp)
129  {
130  (void)fprintf(stderr, "Could not open '%s' for writing.\n", fname);
131  return -1;
132  }
133 
134  /* The tag used as header in the manpage */
135  (void)fprintf(fp, ".SH \"OPTIONS\"\n");
136 
137  if (elements < 2)
138  {
139  (void)fprintf(stderr, "The argument array 'args' is empty, writing an empty file.\n");
140  elements = 1;
141  }
142 
143  for (size_t x = 0; x < elements - 1; x++)
144  {
145  const COMMAND_LINE_ARGUMENT_A* arg = &global_cmd_args[x];
146  char* name = tr_esc_str(arg->Name, FALSE);
147  char* alias = tr_esc_str(arg->Alias, FALSE);
148  char* format = tr_esc_str(arg->Format, TRUE);
149  char* text = tr_esc_str(arg->Text, FALSE);
150 
151  (void)fprintf(fp, ".PP\n");
152  bool first = true;
153  do
154  {
155  (void)fprintf(fp, "%s\\fB", first ? "" : ", ");
156  first = false;
157  if (arg->Flags == COMMAND_LINE_VALUE_BOOL)
158  (void)fprintf(fp, "%s", arg->Default ? "\\-" : "+");
159  else
160  (void)fprintf(fp, "/");
161 
162  (void)fprintf(fp, "%s\\fR", name);
163 
164  if (format)
165  {
166  if (arg->Flags == COMMAND_LINE_VALUE_OPTIONAL)
167  (void)fprintf(fp, "[");
168 
169  (void)fprintf(fp, ":%s", format);
170 
171  if (arg->Flags == COMMAND_LINE_VALUE_OPTIONAL)
172  (void)fprintf(fp, "]");
173  }
174 
175  if (alias == name)
176  break;
177 
178  free(name);
179  name = alias;
180  } while (alias);
181  (void)fprintf(fp, "\n");
182 
183  if (text)
184  {
185  (void)fprintf(fp, ".RS 4\n");
186  const int hasText = text && (strnlen(text, 2) > 0);
187  if (hasText)
188  (void)fprintf(fp, "%s", text);
189 
190  if (arg->Flags & COMMAND_LINE_VALUE_BOOL &&
191  (!arg->Default || arg->Default == BoolValueTrue))
192  (void)fprintf(fp, " (default:%s)\n", arg->Default ? "on" : "off");
193  else if (arg->Default)
194  {
195  char* value = tr_esc_str(arg->Default, FALSE);
196  (void)fprintf(fp, " (default:%s)\n", value);
197  free(value);
198  }
199  else if (hasText)
200  (void)fprintf(fp, "\n");
201  }
202 
203  (void)fprintf(fp, ".RE\n");
204 
205  free(name);
206  free(format);
207  free(text);
208  }
209 
210  (void)fclose(fp);
211 
212  (void)fprintf(stdout, "successfully generated '%s'\n", fname);
213  return 0;
214 }