]> granicus.if.org Git - postgresql/blob - src/backend/utils/misc/help_config.c
Message editing: remove gratuitous variations in message wording, standardize
[postgresql] / src / backend / utils / misc / help_config.c
1 /*-------------------------------------------------------------------------
2  * help_config.c
3  *
4  * Displays available options under grand unified configuration scheme
5  *
6  * The purpose of this option is to list, sort, and make searchable, all
7  * runtime options available to Postgresql, by their description and grouping.
8  *
9  * Valid command-line options to this program:
10  *
11  *      none            : All available variables are sorted by group and name
12  *                                and formatted nicely. ( for human consumption )
13  *      <string>        : list all the variables whose name matches this string
14  *      -g <string> : list all the variables whose group matches this string
15  *      -l                      : lists all currently defined groups and terminates
16  *      -G                      : no sort by groups (you get strict name order, instead)
17  *      -m                      : output the list in Machine friendly format, with a header row
18  *      -M                      : same as m, except no header
19  *      -h                      : help
20  *
21  * Options whose flag bits are set to GUC_NO_SHOW_ALL, GUC_NOT_IN_SAMPLE,
22  * or GUC_DISALLOW_IN_FILE are not displayed, unless the user specifically
23  * requests that variable by name
24  *
25  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
26  *
27  * IDENTIFICATION
28  *        $Header: /cvsroot/pgsql/src/backend/utils/misc/help_config.c,v 1.6 2003/09/25 06:58:06 petere Exp $
29  *
30  *-------------------------------------------------------------------------
31  */
32 #include "postgres.h"
33
34 #include <fcntl.h>
35 #ifdef HAVE_GETOPT_H
36 #include <getopt.h>
37 #endif
38 #include <errno.h>
39 #include <float.h>
40 #include <limits.h>
41 #include <unistd.h>
42
43 #include "utils/guc.h"
44 #include "utils/guc_tables.h"
45 #include "utils/help_config.h"
46
47 extern int      optind;
48 extern char *optarg;
49
50
51 /*
52  * The following char constructs provide the different formats the variables
53  * can be outputted in.
54  */
55 enum outputFormat
56 {
57         HUMAN_OUTPUT,
58         MACHINE_OUTPUT
59 };
60
61 static const char *const GENERIC_FORMAT[] = {
62         gettext_noop("Name:        %-20s\nContext:     %-20s\nGroup:       %-20s\n"),
63         "%s\t%s\t%s\t"
64 };
65 static const char *const GENERIC_DESC[] = {
66         gettext_noop("Description: %s\n%s\n"),
67         "%s\t%s\n"
68 };
69 static const char *const BOOL_FORMAT[] = {
70         gettext_noop("Type:        Boolean\nReset value: %-s\n"),
71         "BOOL\t%s\t\t\t"
72 };
73 static const char *const INT_FORMAT[] = {
74         gettext_noop("Type:        integer\nReset value: %-20d\nMin value:   %-20d\nMax value:   %-20d\n"),
75         "INT\t%d\t%d\t%d\t"
76 };
77 static const char *const REAL_FORMAT[] = {
78         gettext_noop("Type:        real\nReset value: %-20g\nMin value:   %-20g\nMax value:   %-20g\n"),
79         "REAL\t%g\t%g\t%g\t"
80 };
81 static const char *const STRING_FORMAT[] = {
82         gettext_noop("Type:        string\nReset value: %-s\n"),
83         "STRING\t%s\t\t\t"
84 };
85 static const char *const COLUMN_HEADER[] = {
86         "",
87         gettext_noop("NAME\tCONTEXT\tGROUP\tTYPE\tRESET_VALUE\tMIN\tMAX\tSHORT_DESCRIPTION\tLONG_DESCRIPTION\n")
88 };
89 static const char *const ROW_SEPARATOR[] = {
90         "------------------------------------------------------------\n",
91         ""
92 };
93
94 /*
95  * Variables loaded from the command line
96  */
97 static char *nameString = NULL; /* The var name pattern to match */
98 static bool nameRegexBool = false;              /* Match the name pattern as a
99                                                                                  * regex */
100 static char *groupString = NULL;        /* The var group pattern to match */
101 static bool groupRegexBool = false;             /* Match the group pattern as a
102                                                                                  * regex */
103 static enum outputFormat outFormat = HUMAN_OUTPUT;
104 static bool suppressAllHeaders = false; /* MACHINE_OUTPUT output, no
105                                                                                  * column headers */
106 static bool groupResults = true;        /* sort result list by groups */
107
108
109 /*
110  * This union allows us to mix the numerous different types of structs
111  * that we are organizing.
112  */
113 typedef union
114 {
115         struct config_generic generic;
116         struct config_bool bool;
117         struct config_real real;
118         struct config_int integer;
119         struct config_string string;
120 } mixedStruct;
121
122
123 /* function prototypes */
124 static bool varMatches(mixedStruct *structToTest);
125 static int      compareMixedStructs(const void *, const void *);
126 static mixedStruct **varsToDisplay(int *resultListSize);
127 static const char *usageErrMsg(void);
128 static void helpMessage(void);
129 static void listAllGroups(void);
130 static void printGenericHead(struct config_generic structToPrint);
131 static void printGenericFoot(struct config_generic structToPrint);
132 static void printMixedStruct(mixedStruct *structToPrint);
133 static bool displayStruct(mixedStruct *structToDisplay);
134
135
136 /*
137  * Reads in the the command line options and sets the state of the program
138  * accordingly. Initializes the result list and sorts it.
139  */
140 int
141 GucInfoMain(int argc, char *argv[])
142 {
143         mixedStruct **varList;
144         int                     resultListSize;
145         int                     c;
146         int                     i;
147
148         while ((c = getopt(argc, argv, "g:rGmMlh")) != -1)
149         {
150                 switch (c)
151                 {
152                         case 'g':
153                                 groupString = optarg;
154                                 break;
155                         case 'r':                       /* not actually implemented yet */
156                                 nameRegexBool = true;
157                                 break;
158                         case 'G':
159                                 groupResults = false;
160                                 break;
161                         case 'm':
162                                 outFormat = MACHINE_OUTPUT;
163                                 break;
164                         case 'M':
165                                 outFormat = MACHINE_OUTPUT;
166                                 suppressAllHeaders = true;
167                                 break;
168                         case 'l':
169                                 listAllGroups();
170                                 exit(0);
171                         case 'h':
172                                 helpMessage();
173                                 exit(0);
174
175                         default:
176                                 fprintf(stderr, gettext("%s \n Try -h for further details\n"), usageErrMsg());
177                                 exit(1);
178                 }
179         }
180
181         if (optind < argc)
182                 nameString = argv[optind];
183
184         /* get the list of variables that match the user's specs. */
185         varList = varsToDisplay(&resultListSize);
186
187         /* sort them by group if desired */
188         /* (without this, we get the original sort by name from guc.c) */
189         if (groupResults)
190                 qsort(varList, resultListSize,
191                           sizeof(mixedStruct *), compareMixedStructs);
192
193         /* output the results */
194         if (!suppressAllHeaders)
195                 printf(gettext(COLUMN_HEADER[outFormat]));
196
197         for (i = 0; varList[i] != NULL; i++)
198         {
199                 printf(gettext(ROW_SEPARATOR[outFormat]));
200                 printMixedStruct(varList[i]);
201         }
202
203         return 0;
204 }
205
206
207 /*
208  * This function is used to compare two mixedStruct types. It compares based
209  * on the value of the 'group' field, and then the name of the variable.
210  * Each void* is expected to be a pointer to a pointer to a struct.
211  * (This is because it is used by qsort to sort an array of struct pointers)
212  *
213  * Returns an integer less than, equal to, or greater than zero if the first
214  * argument (struct1) is considered to be respectively less than, equal to,
215  * or greater than the second (struct2). The comparison is made frist on the
216  * value of struct{1,2}.generic.group and then struct{1,2}.generic.name. The
217  * groups will display in the order they are defined in enum config_group
218  */
219 static int
220 compareMixedStructs(const void *struct1, const void *struct2)
221 {
222         mixedStruct *structVar1 = *(mixedStruct **) struct1;
223         mixedStruct *structVar2 = *(mixedStruct **) struct2;
224
225         if (structVar1->generic.group > structVar2->generic.group)
226                 return 1;
227         else if (structVar1->generic.group < structVar2->generic.group)
228                 return -1;
229         else
230                 return strcmp(structVar1->generic.name, structVar2->generic.name);
231 }
232
233
234 /*
235  * This function returns a complete list of all the variables to display,
236  * according to what the user wants to see.
237  */
238 static mixedStruct **
239 varsToDisplay(int *resultListSize)
240 {
241         mixedStruct **resultList;
242         int                     arrayIndex;
243         int                     i;
244
245         /* Initialize the guc_variables[] array */
246         build_guc_variables();
247
248         /* Extract just the ones we want to display */
249         resultList = malloc((num_guc_variables + 1) * sizeof(mixedStruct *));
250         arrayIndex = 0;
251
252         for (i = 0; i < num_guc_variables; i++)
253         {
254                 mixedStruct *var = (mixedStruct *) guc_variables[i];
255
256                 if (varMatches(var))
257                         resultList[arrayIndex++] = var;
258         }
259
260         /* add an end marker */
261         resultList[arrayIndex] = NULL;
262
263         *resultListSize = arrayIndex;
264         return resultList;
265 }
266
267
268 /*
269  * This function will return true if the struct passed to it
270  * should be displayed to the user.
271  *
272  * The criteria to determine if the struct should not be displayed is:
273  *      + It's flag bits are set to GUC_NO_SHOW_ALL
274  *      + It's flag bits are set to GUC_NOT_IN_SAMPLE
275  *      + It's flag bits are set to GUC_DISALLOW_IN_FILE
276  */
277 static bool
278 displayStruct(mixedStruct *structToDisplay)
279 {
280         if (structToDisplay->generic.flags & (GUC_NO_SHOW_ALL |
281                                                                                   GUC_NOT_IN_SAMPLE |
282                                                                                   GUC_DISALLOW_IN_FILE))
283                 return false;
284         else
285                 return true;
286 }
287
288
289 /*
290  * Used to determine if a variable matches the user's specifications (stored in
291  * global variables). Returns true if this particular variable information should
292  * be returned to the user.
293  */
294 static bool
295 varMatches(mixedStruct *structToTest)
296 {
297         bool            matches = false;
298         bool            specificSearch = false; /* This is true if the user
299                                                                                  * searched for a variable in
300                                                                                  * particular. */
301
302         if (nameString != NULL && !nameRegexBool)
303         {
304                 if (strstr(structToTest->generic.name, nameString) != NULL)
305                 {
306                         matches = true;
307                         specificSearch = true;
308                 }
309         }
310
311         if (nameString != NULL && nameRegexBool)
312         {
313                 /* We do not support this option yet */
314         }
315
316         if (groupString != NULL && !groupRegexBool)
317         {
318                 if (strstr(config_group_names[structToTest->generic.group], groupString) != NULL)
319                 {
320                         if (nameString != NULL)
321                                 matches = (matches && true);
322                         else
323                                 matches = true;
324                 }
325                 else
326                         matches = false;
327         }
328
329         if (groupString != NULL && groupRegexBool)
330         {
331                 /* We do not support this option yet */
332         }
333
334         /* return all variables */
335         if (nameString == NULL && groupString == NULL)
336                 matches = true;
337
338         if (specificSearch)
339                 return matches;
340         else
341                 return matches && displayStruct(structToTest);
342 }
343
344
345 /*
346  * This function prints out the generic struct passed to it. It will print out
347  * a different format, depending on what the user wants to see.
348  */
349 static void
350 printMixedStruct(mixedStruct *structToPrint)
351 {
352         printGenericHead(structToPrint->generic);
353
354         switch (structToPrint->generic.vartype)
355         {
356
357                 case PGC_BOOL:
358                         printf(gettext(BOOL_FORMAT[outFormat]),
359                                    (structToPrint->bool.reset_val == 0) ?
360                                    gettext("FALSE") : gettext("TRUE"));
361                         break;
362
363                 case PGC_INT:
364                         printf(gettext(INT_FORMAT[outFormat]),
365                                    structToPrint->integer.reset_val,
366                                    structToPrint->integer.min,
367                                    structToPrint->integer.max);
368                         break;
369
370                 case PGC_REAL:
371                         printf(gettext(REAL_FORMAT[outFormat]),
372                                    structToPrint->real.reset_val,
373                                    structToPrint->real.min,
374                                    structToPrint->real.max);
375                         break;
376
377                 case PGC_STRING:
378                         printf(gettext(STRING_FORMAT[outFormat]),
379                                    structToPrint->string.boot_val);
380                         break;
381
382                 default:
383                         printf(gettext("Unrecognized variable type!\n"));
384                         break;
385         }
386
387         printGenericFoot(structToPrint->generic);
388 }
389
390 static void
391 printGenericHead(struct config_generic structToPrint)
392 {
393         printf(gettext(GENERIC_FORMAT[outFormat]),
394                    structToPrint.name,
395                    GucContext_Names[structToPrint.context],
396                    gettext(config_group_names[structToPrint.group]));
397 }
398
399 static void
400 printGenericFoot(struct config_generic sPrint)
401 {
402         printf(gettext(GENERIC_DESC[outFormat]),
403                    (sPrint.short_desc == NULL) ? "" : gettext(sPrint.short_desc),
404                    (sPrint.long_desc == NULL) ? "" : gettext(sPrint.long_desc));
405 }
406
407 static void
408 listAllGroups(void)
409 {
410         int                     i;
411
412         printf(gettext("All currently defined groups\n"));
413         printf(gettext("----------------------------\n"));
414         for (i = 0; config_group_names[i] != NULL; i++)
415                 printf(gettext("%s\n"), gettext(config_group_names[i]));
416 }
417
418 static const char *
419 usageErrMsg(void)
420 {
421         return gettext("Usage for --help-config option: [-h] [-g <group>] [-l] [-G] [-m] [-M] [string]\n");
422 }
423
424 static void
425 helpMessage(void)
426 {
427         printf(gettext("Description:\n"
428                                    "--help-config displays all the runtime options available in PostgreSQL.\n"
429                                    "It groups them by category and sorts them by name. If available, it will\n"
430                                    "present a short description, default, max and min values as well as other\n"
431                                    "information about each option.\n\n"
432                                    "With no options specified, it will output all available runtime options\n"
433                                    "in human friendly format, grouped by category and sorted by name.\n\n"
434
435                                    "%s\n"
436
437                                    "General Options:\n"
438                         "  [string]     All options with names that match this string\n"
439                            "  -g GROUP  All options in categories that match GROUP\n"
440                                    "  -l        Prints list of all groups / subgroups\n"
441                                    "  -h        Prints this help message\n"
442                                    "\nOutput Options:\n"
443                                    "  -G        Do not group by category\n"
444                         "  -m           Machine friendly format: tab separated fields\n"
445                                    "  -M        Same as m, except header with column names is suppressed\n"),
446                    usageErrMsg()
447                 );
448 }