clargs.c revision 0bbfda8a
10bbfda8aSnia/*
20bbfda8aSnia * Command-line arg handling
30bbfda8aSnia */
40bbfda8aSnia
50bbfda8aSnia#include "ctwm.h"
60bbfda8aSnia
70bbfda8aSnia#include <getopt.h>
80bbfda8aSnia#include <stdio.h>
90bbfda8aSnia#include <stdlib.h>
100bbfda8aSnia#include <string.h>
110bbfda8aSnia
120bbfda8aSnia#include "clargs.h"
130bbfda8aSnia#include "ctopts.h"
140bbfda8aSnia#include "deftwmrc.h"
150bbfda8aSnia#include "screen.h"
160bbfda8aSnia#include "version.h"
170bbfda8aSnia
180bbfda8aSniastatic void usage(void) __attribute__((noreturn));
190bbfda8aSniastatic void print_version(void);
200bbfda8aSniastatic void DisplayInfo(void);
210bbfda8aSniastatic void dump_default_config(void);
220bbfda8aSnia
230bbfda8aSnia
240bbfda8aSnia/*
250bbfda8aSnia * Command-line args.  Initialize with useful default values.
260bbfda8aSnia */
270bbfda8aSniactwm_cl_args CLarg = {
280bbfda8aSnia	.MultiScreen     = true,
290bbfda8aSnia	.Monochrome      = false,
300bbfda8aSnia	.cfgchk          = false,
310bbfda8aSnia	.InitFile        = NULL,
320bbfda8aSnia	.display_name    = NULL,
330bbfda8aSnia	.PrintErrorMessages = false,
340bbfda8aSnia#ifdef DEBUG
350bbfda8aSnia	.ShowWelcomeWindow  = false,
360bbfda8aSnia#else
370bbfda8aSnia	.ShowWelcomeWindow  = true,
380bbfda8aSnia#endif
390bbfda8aSnia	.is_captive      = false,
400bbfda8aSnia	.capwin          = (Window) 0,
410bbfda8aSnia	.captivename     = NULL,
420bbfda8aSnia#ifdef USEM4
430bbfda8aSnia	.KeepTmpFile     = false,
440bbfda8aSnia	.keepM4_filename = NULL,
450bbfda8aSnia	.GoThroughM4     = true,
460bbfda8aSnia#endif
470bbfda8aSnia#ifdef EWMH
480bbfda8aSnia	.ewmh_replace    = false,
490bbfda8aSnia#endif
500bbfda8aSnia	.client_id       = NULL,
510bbfda8aSnia	.restore_filename = NULL,
520bbfda8aSnia};
530bbfda8aSnia
540bbfda8aSnia
550bbfda8aSnia
560bbfda8aSnia/*
570bbfda8aSnia * Parse them out and setup CLargs.
580bbfda8aSnia */
590bbfda8aSniavoid
600bbfda8aSniaclargs_parse(int argc, char *argv[])
610bbfda8aSnia{
620bbfda8aSnia	int ch, optidx;
630bbfda8aSnia
640bbfda8aSnia	/*
650bbfda8aSnia	 * Setup long options for arg parsing
660bbfda8aSnia	 */
670bbfda8aSnia	static struct option long_options[] = {
680bbfda8aSnia		/* Simple flags */
690bbfda8aSnia		{ "single",    no_argument,       NULL, 0 },
700bbfda8aSnia		{ "mono",      no_argument,       NULL, 0 },
710bbfda8aSnia		{ "verbose",   no_argument,       NULL, 'v' },
720bbfda8aSnia		{ "quiet",     no_argument,       NULL, 'q' },
730bbfda8aSnia		{ "nowelcome", no_argument,       NULL, 'W' },
740bbfda8aSnia
750bbfda8aSnia		/* Config/file related */
760bbfda8aSnia		{ "file",      required_argument, NULL, 'f' },
770bbfda8aSnia		{ "cfgchk",    no_argument,       NULL, 0 },
780bbfda8aSnia
790bbfda8aSnia		/* Show something and exit right away */
800bbfda8aSnia		{ "help",      no_argument,       NULL, 'h' },
810bbfda8aSnia		{ "version",   no_argument,       NULL, 0 },
820bbfda8aSnia		{ "info",      no_argument,       NULL, 0 },
830bbfda8aSnia		{ "dumpcfg",   no_argument,       NULL, 0 },
840bbfda8aSnia
850bbfda8aSnia		/* Misc control bits */
860bbfda8aSnia		{ "display",   required_argument, NULL, 'd' },
870bbfda8aSnia		{ "window",    optional_argument, NULL, 'w' },
880bbfda8aSnia		{ "name",      required_argument, NULL, 0 },
890bbfda8aSnia		{ "xrm",       required_argument, NULL, 0 },
900bbfda8aSnia
910bbfda8aSnia#ifdef EWMH
920bbfda8aSnia		{ "replace",   no_argument,       NULL, 0 },
930bbfda8aSnia#endif
940bbfda8aSnia
950bbfda8aSnia		/* M4 control params */
960bbfda8aSnia#ifdef USEM4
970bbfda8aSnia		{ "keep-defs", no_argument,       NULL, 'k' },
980bbfda8aSnia		{ "keep",      required_argument, NULL, 'K' },
990bbfda8aSnia		{ "nom4",      no_argument,       NULL, 'n' },
1000bbfda8aSnia#endif
1010bbfda8aSnia
1020bbfda8aSnia		/* Random session-related bits */
1030bbfda8aSnia		{ "clientId",  required_argument, NULL, 0 },
1040bbfda8aSnia		{ "restore",   required_argument, NULL, 0 },
1050bbfda8aSnia
1060bbfda8aSnia		{ NULL,        0,                 NULL, 0 },
1070bbfda8aSnia	};
1080bbfda8aSnia
1090bbfda8aSnia
1100bbfda8aSnia	/*
1110bbfda8aSnia	 * Short aliases for some
1120bbfda8aSnia	 *
1130bbfda8aSnia	 * I assume '::' for optional args is portable; getopt_long(3)
1140bbfda8aSnia	 * doesn't describe it, but it's a GNU extension for getopt(3).
1150bbfda8aSnia	 */
1160bbfda8aSnia	const char *short_options = "vqWf:hd:w::"
1170bbfda8aSnia#ifdef USEM4
1180bbfda8aSnia	                            "kK:n"
1190bbfda8aSnia#endif
1200bbfda8aSnia	                            ;
1210bbfda8aSnia
1220bbfda8aSnia
1230bbfda8aSnia	/*
1240bbfda8aSnia	 * Backward-compat cheat: accept a few old-style long args if they
1250bbfda8aSnia	 * came first.  Of course, this assumed argv[x] is editable, which on
1260bbfda8aSnia	 * most systems it is, and C99 requires it.
1270bbfda8aSnia	 */
1280bbfda8aSnia	if(argc > 1) {
1290bbfda8aSnia#define CHK(x) else if(strcmp(argv[1], (x)) == 0)
1300bbfda8aSnia		if(0) {
1310bbfda8aSnia			/* nada */
1320bbfda8aSnia		}
1330bbfda8aSnia		CHK("-version") {
1340bbfda8aSnia			print_version();
1350bbfda8aSnia			exit(0);
1360bbfda8aSnia		}
1370bbfda8aSnia		CHK("-info") {
1380bbfda8aSnia			DisplayInfo();
1390bbfda8aSnia			exit(0);
1400bbfda8aSnia		}
1410bbfda8aSnia		CHK("-cfgchk") {
1420bbfda8aSnia			CLarg.cfgchk = true;
1430bbfda8aSnia			*argv[1] = '\0';
1440bbfda8aSnia		}
1450bbfda8aSnia		CHK("-display") {
1460bbfda8aSnia			if(argc <= 2 || strlen(argv[2]) < 1) {
1470bbfda8aSnia				usage();
1480bbfda8aSnia			}
1490bbfda8aSnia			CLarg.display_name = strdup(argv[2]);
1500bbfda8aSnia
1510bbfda8aSnia			*argv[1] = '\0';
1520bbfda8aSnia			*argv[2] = '\0';
1530bbfda8aSnia		}
1540bbfda8aSnia#undef CHK
1550bbfda8aSnia	}
1560bbfda8aSnia
1570bbfda8aSnia
1580bbfda8aSnia	/*
1590bbfda8aSnia	 * Parse out the args
1600bbfda8aSnia	 */
1610bbfda8aSnia	optidx = 0;
1620bbfda8aSnia	while((ch = getopt_long(argc, argv, short_options, long_options,
1630bbfda8aSnia	                        &optidx)) != -1) {
1640bbfda8aSnia		switch(ch) {
1650bbfda8aSnia			/* First handle the simple cases that have short args */
1660bbfda8aSnia			case 'v':
1670bbfda8aSnia				CLarg.PrintErrorMessages = true;
1680bbfda8aSnia				break;
1690bbfda8aSnia			case 'q':
1700bbfda8aSnia				CLarg.PrintErrorMessages = false;
1710bbfda8aSnia				break;
1720bbfda8aSnia			case 'W':
1730bbfda8aSnia				CLarg.ShowWelcomeWindow = false;
1740bbfda8aSnia				break;
1750bbfda8aSnia			case 'f':
1760bbfda8aSnia				CLarg.InitFile = optarg;
1770bbfda8aSnia				break;
1780bbfda8aSnia			case 'h':
1790bbfda8aSnia				usage();
1800bbfda8aSnia			case 'd':
1810bbfda8aSnia				CLarg.display_name = optarg;
1820bbfda8aSnia				break;
1830bbfda8aSnia			case 'w':
1840bbfda8aSnia				CLarg.is_captive = true;
1850bbfda8aSnia				CLarg.MultiScreen = false;
1860bbfda8aSnia				if(optarg != NULL) {
1870bbfda8aSnia					sscanf(optarg, "%x", (unsigned int *)&CLarg.capwin);
1880bbfda8aSnia					/* Failure will just leave capwin as initialized */
1890bbfda8aSnia				}
1900bbfda8aSnia				break;
1910bbfda8aSnia
1920bbfda8aSnia#ifdef USEM4
1930bbfda8aSnia			/* Args that only mean anything if we're built with m4 */
1940bbfda8aSnia			case 'k':
1950bbfda8aSnia				CLarg.KeepTmpFile = true;
1960bbfda8aSnia				break;
1970bbfda8aSnia			case 'K':
1980bbfda8aSnia				CLarg.keepM4_filename = optarg;
1990bbfda8aSnia				break;
2000bbfda8aSnia			case 'n':
2010bbfda8aSnia				CLarg.GoThroughM4 = false;
2020bbfda8aSnia				break;
2030bbfda8aSnia#endif
2040bbfda8aSnia
2050bbfda8aSnia
2060bbfda8aSnia			/*
2070bbfda8aSnia			 * Now the stuff that doesn't have short variants.
2080bbfda8aSnia			 */
2090bbfda8aSnia			case 0:
2100bbfda8aSnia
2110bbfda8aSnia#define IFIS(x) if(strcmp(long_options[optidx].name, (x)) == 0)
2120bbfda8aSnia				/* Simple flag-setting */
2130bbfda8aSnia				IFIS("single") {
2140bbfda8aSnia					CLarg.MultiScreen = false;
2150bbfda8aSnia					break;
2160bbfda8aSnia				}
2170bbfda8aSnia				IFIS("mono") {
2180bbfda8aSnia					CLarg.Monochrome = true;
2190bbfda8aSnia					break;
2200bbfda8aSnia				}
2210bbfda8aSnia				IFIS("cfgchk") {
2220bbfda8aSnia					CLarg.cfgchk = true;
2230bbfda8aSnia					break;
2240bbfda8aSnia				}
2250bbfda8aSnia#ifdef EWMH
2260bbfda8aSnia				IFIS("replace") {
2270bbfda8aSnia					CLarg.ewmh_replace = true;
2280bbfda8aSnia					break;
2290bbfda8aSnia				}
2300bbfda8aSnia#endif
2310bbfda8aSnia
2320bbfda8aSnia				/* Simple value-setting */
2330bbfda8aSnia				IFIS("name") {
2340bbfda8aSnia					CLarg.captivename = optarg;
2350bbfda8aSnia					break;
2360bbfda8aSnia				}
2370bbfda8aSnia				IFIS("clientId") {
2380bbfda8aSnia					CLarg.client_id = optarg;
2390bbfda8aSnia					break;
2400bbfda8aSnia				}
2410bbfda8aSnia				IFIS("restore") {
2420bbfda8aSnia					CLarg.restore_filename = optarg;
2430bbfda8aSnia					break;
2440bbfda8aSnia				}
2450bbfda8aSnia
2460bbfda8aSnia				/* Some immediate actions */
2470bbfda8aSnia				IFIS("version") {
2480bbfda8aSnia					print_version();
2490bbfda8aSnia					exit(0);
2500bbfda8aSnia				}
2510bbfda8aSnia				IFIS("info") {
2520bbfda8aSnia					DisplayInfo();
2530bbfda8aSnia					exit(0);
2540bbfda8aSnia				}
2550bbfda8aSnia				IFIS("dumpcfg") {
2560bbfda8aSnia					dump_default_config();
2570bbfda8aSnia					exit(0);
2580bbfda8aSnia				}
2590bbfda8aSnia
2600bbfda8aSnia				/* Misc */
2610bbfda8aSnia				IFIS("xrm") {
2620bbfda8aSnia					/*
2630bbfda8aSnia					 * Quietly ignored by us; Xlib processes it
2640bbfda8aSnia					 * internally in XtToolkitInitialize();
2650bbfda8aSnia					 */
2660bbfda8aSnia					break;
2670bbfda8aSnia				}
2680bbfda8aSnia#undef IFIS
2690bbfda8aSnia
2700bbfda8aSnia				/*
2710bbfda8aSnia				 * Some choices may just be internally setting a flag.
2720bbfda8aSnia				 * We have none right now, but leave this in case we grow
2730bbfda8aSnia				 * more later.
2740bbfda8aSnia				 */
2750bbfda8aSnia				if(long_options[optidx].flag != NULL) {
2760bbfda8aSnia					break;
2770bbfda8aSnia				}
2780bbfda8aSnia
2790bbfda8aSnia				/* Don't think it should be possible to get here... */
2800bbfda8aSnia				fprintf(stderr, "Internal error in getopt: '%s' unhandled.\n",
2810bbfda8aSnia				        long_options[optidx].name);
2820bbfda8aSnia				usage();
2830bbfda8aSnia
2840bbfda8aSnia			/* Something totally unexpected */
2850bbfda8aSnia			case '?':
2860bbfda8aSnia				/* getopt_long() already printed an error */
2870bbfda8aSnia				usage();
2880bbfda8aSnia
2890bbfda8aSnia			default:
2900bbfda8aSnia				/* Uhhh...  */
2910bbfda8aSnia				fprintf(stderr, "Internal error: getopt confused us.\n");
2920bbfda8aSnia				usage();
2930bbfda8aSnia		}
2940bbfda8aSnia	}
2950bbfda8aSnia
2960bbfda8aSnia
2970bbfda8aSnia	/* Should do it */
2980bbfda8aSnia	return;
2990bbfda8aSnia}
3000bbfda8aSnia
3010bbfda8aSnia
3020bbfda8aSnia/*
3030bbfda8aSnia * Sanity check CLarg's
3040bbfda8aSnia */
3050bbfda8aSniavoid
3060bbfda8aSniaclargs_check(void)
3070bbfda8aSnia{
3080bbfda8aSnia
3090bbfda8aSnia#ifdef USEM4
3100bbfda8aSnia	/* If we're not doing m4, don't specify m4 options */
3110bbfda8aSnia	if(!CLarg.GoThroughM4) {
3120bbfda8aSnia		if(CLarg.KeepTmpFile) {
3130bbfda8aSnia			fprintf(stderr, "--keep-defs is incompatible with --nom4.\n");
3140bbfda8aSnia			usage();
3150bbfda8aSnia		}
3160bbfda8aSnia		if(CLarg.keepM4_filename) {
3170bbfda8aSnia			fprintf(stderr, "--keep is incompatible with --nom4.\n");
3180bbfda8aSnia			usage();
3190bbfda8aSnia		}
3200bbfda8aSnia	}
3210bbfda8aSnia#endif
3220bbfda8aSnia
3230bbfda8aSnia	/* If we're not captive, captivename is meaningless too */
3240bbfda8aSnia	if(CLarg.captivename && !CLarg.is_captive) {
3250bbfda8aSnia		fprintf(stderr, "--name is meaningless without --window.\n");
3260bbfda8aSnia		usage();
3270bbfda8aSnia	}
3280bbfda8aSnia
3290bbfda8aSnia	/* Guess that's it */
3300bbfda8aSnia	return;
3310bbfda8aSnia}
3320bbfda8aSnia
3330bbfda8aSnia
3340bbfda8aSnia/*
3350bbfda8aSnia * Small utils only currently used in this file.  Over time they may need
3360bbfda8aSnia * to be exported, if we start using them from more places.
3370bbfda8aSnia */
3380bbfda8aSniastatic void
3390bbfda8aSniausage(void)
3400bbfda8aSnia{
3410bbfda8aSnia	/* How far to indent continuation lines */
3420bbfda8aSnia	int llen = 10;
3430bbfda8aSnia
3440bbfda8aSnia	fprintf(stderr, "usage: %s [(--display | -d) dpy]  "
3450bbfda8aSnia#ifdef EWMH
3460bbfda8aSnia	        "[--replace]  "
3470bbfda8aSnia#endif
3480bbfda8aSnia	        "[--single]\n", ProgramName);
3490bbfda8aSnia
3500bbfda8aSnia	fprintf(stderr, "%*s[(--file | -f) initfile]  [--cfgchk]  [--dumpcfg]\n",
3510bbfda8aSnia	        llen, "");
3520bbfda8aSnia
3530bbfda8aSnia#ifdef USEM4
3540bbfda8aSnia	fprintf(stderr, "%*s[--nom4 | -n]  [--keep-defs | -k]  "
3550bbfda8aSnia	        "[(--keep | -K) m4file]\n", llen, "");
3560bbfda8aSnia#endif
3570bbfda8aSnia
3580bbfda8aSnia	fprintf(stderr, "%*s[--verbose | -v]  [--quiet | -q]  [--mono]  "
3590bbfda8aSnia	        "[--xrm resource]\n", llen, "");
3600bbfda8aSnia
3610bbfda8aSnia	fprintf(stderr, "%*s[--version]  [--info]  [--nowelcome | -W]\n",
3620bbfda8aSnia	        llen, "");
3630bbfda8aSnia
3640bbfda8aSnia	fprintf(stderr, "%*s[(--window | -w) [win-id]]  [--name name]\n", llen, "");
3650bbfda8aSnia
3660bbfda8aSnia	/* Semi-intentionally not documenting --clientId/--restore */
3670bbfda8aSnia
3680bbfda8aSnia	fprintf(stderr, "%*s[--help]\n", llen, "");
3690bbfda8aSnia
3700bbfda8aSnia
3710bbfda8aSnia	exit(1);
3720bbfda8aSnia}
3730bbfda8aSnia
3740bbfda8aSnia
3750bbfda8aSniastatic void
3760bbfda8aSniaprint_version(void)
3770bbfda8aSnia{
3780bbfda8aSnia	printf("ctwm %s\n", VersionNumberFull);
3790bbfda8aSnia	if(VCSType && VCSRevision) {
3800bbfda8aSnia		printf(" (%s:%s)\n", VCSType, VCSRevision);
3810bbfda8aSnia	}
3820bbfda8aSnia}
3830bbfda8aSnia
3840bbfda8aSnia
3850bbfda8aSniastatic void
3860bbfda8aSniaDisplayInfo(void)
3870bbfda8aSnia{
3880bbfda8aSnia	char *ctopts;
3890bbfda8aSnia
3900bbfda8aSnia	printf("Twm version:  %s\n", TwmVersion);
3910bbfda8aSnia
3920bbfda8aSnia	ctopts = ctopts_string(" ");
3930bbfda8aSnia	printf("Compile time options : %s\n", ctopts);
3940bbfda8aSnia	free(ctopts);
3950bbfda8aSnia}
3960bbfda8aSnia
3970bbfda8aSnia
3980bbfda8aSniastatic void
3990bbfda8aSniadump_default_config(void)
4000bbfda8aSnia{
4010bbfda8aSnia	int i;
4020bbfda8aSnia
4030bbfda8aSnia	for(i = 0 ; defTwmrc[i] != NULL ; i++) {
4040bbfda8aSnia		printf("%s\n", defTwmrc[i]);
4050bbfda8aSnia	}
4060bbfda8aSnia}
407