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