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