2 * Autotitle - copyright (C)1991 Ian Jackson (iwj10@phx.cam.ac.uk)
4 * Automatically set window titles, prompts etc.
6 * Will output the string in AUTOTITLE_STDOUT (in the environment)
7 * to standard output, eg for use in your prompt.
8 * If it can find your X server or your TERM is xterm it will
9 * set your icon name to AUTOTITLE_ICON and your window name
10 * to AUTOTITLE_WINDOW.
12 * Defaults are, respectively,
14 * "%h: %d2. %Y.[U..[U..[D./..%X.L]..R]./.."
15 * "%h - %d. %Y.[U..[U..[D./..%X.L]..R]./.. %U%?G(%G)%!"
17 * Environment configuration strings work a bit like printf etc:
19 * Conversion characters
20 * %x Left edge position of window (if WINDOWID and DISPLAY set).
22 * %X.p..q..r./.s. (pqrstrings)[ len(str)*ypos/(yscreen-ysize+1)+0.5 ]
23 * %Y.p..q..r./.s. Same for x,y. If window is off screen, is string s.
24 * The dots are delimiters - any char allowed, must
25 * be same at both ends of one string p, q or r etc.
26 * Number of strings may be 1..oo but /.string. is mandatory.
27 * %d***. Current directory; examples of ***'s:
28 * %d2. Last two components only
29 * %d~. Display home directory as ~ (as opposed to '' or ~)
30 * %de. Never use PWD environment variable even if it is correct.
31 * %dE. Always use PWD environment variable.
32 * %dU. Use home directory for uid from passwd file, not $HOME
33 * %d3~U. Combination of the above.
35 * %N.p..q..r./.s. Like %Y and %X only for nice value (range 0..39)
40 * %E***. Environment variable ***, or null string.
41 * %m Umask in numerical form (3 digits) (as set by umask)
42 * %M Umask in rwx--- form (shows perms of file opened 777)
43 * %h Hostname, but truncated to just the host, not FQDN
44 * %H Hostname - FQDN if available, otherwise just machine
45 * %?g***%! Do *** if gid != default for this uid
46 * %?G***%! Do *** if gid or group name != $GROUP (or uid's grp if no $GROUP)
47 * %?u***%! Do *** if uid != $USER (or $LOGNAME if no $USER)
48 * %?n***%! Do *** if nice value != 20
49 * %?mXXX***%! Do *** if umask != XXX
50 * %?E###.***%! Do *** if ### is not an environment variable.
57 #include <X11/Xutil.h>
63 #include <sys/types.h>
76 #define forever for(;;)
78 /* #define NOXWINDOWS /* Define this to remove the X handling code */
79 /* #define NODETACH /* Define this to stop autotitle from forking ever */
80 /* #define NOXTERM /* Define this to make autotitle not set xterm's titles */
81 /* #define NOSTDOUT /* Define this to disable the stdout output */
82 #define DEFAULTTITLE "%h - %d. %Y.[U..[U..[D./..%X.L]..R]./.. %U%?G(%G)%!"
83 #define DEFAULTICON "%h: %d2. %Y.[U..[U..[D./..%X.L]..R]./.."
85 #define BUILDMAX 10000
86 #define SMALLBUFMAX 100
90 static char lto_buf[20];
91 char *ltoa(n) long n; { sprintf(lto_buf,"%ld",n); return lto_buf; }
92 char *ltoaoct(n) long n; { sprintf(lto_buf,"%lo",n); return lto_buf; }
94 # define ltoaoct(n) ltostr((n),8)
106 struct geom wg, rg={0,&wg};
108 int X_error_handler();
109 #endif /* !NOXWINDOWS */
111 char *user_name(), *user_nameonly(), *user_home();
114 struct passwd *pwent;
130 char build[BUILDMAX], *bp;
131 char *bp_end= build+BUILDMAX;
141 int iflevel, ifskiplevel;
143 void add_string(), add_number(), add_scaled(), add_currentdir();
144 void add_umask(), detach(), add_envir();
145 char *scaledstr_chop();
148 char *controlstring, *termtype;
151 umsk= umask(0); umask(umsk);
154 mkstring(0,0, "AUTOTITLE_STDOUT","");
156 write(1,build,strlen(build));
158 #endif /* !NOSTDOUT */
161 termtype= getenv("TERM");
162 if (termtype && !strcmp(termtype,"xterm")) {
163 # if !defined(NODETACH) && !defined(NOEARLYDETACH)
169 mkstring("\033]2;","\007", "AUTOTITLE_WINDOW",DEFAULTTITLE);
170 write(2,build,strlen(build));
171 mkstring("\033]1;","\007", "AUTOTITLE_ICON",DEFAULTICON);
172 write(2,build,strlen(build));
173 # if !defined(NODETACH) && defined(NOEARLYDETACH)
177 #endif /* !NOXTERM */
181 # endif /* !NODETACH */
184 mkstring(0,0, "AUTOTITLE_WINDOW",DEFAULTTITLE);
185 XStoreName(display,window,build);
186 mkstring(0,0, "AUTOTITLE_ICON",DEFAULTICON);
187 XSetIconName(display,window,build);
190 #endif /* ~ NOXWINDOWS */
197 void mkstring(initialstring,finalstring,controlenv,controlstring)
198 char *initialstring, *finalstring;
199 char *controlenv, *controlstring;
201 static char *envuser=0, *envstring, *envgroup=0;
202 int inc, chkum, ifskipthis;
203 char smallbuffer[SMALLBUFMAX+1], *p;
205 envstring= getenv(controlenv);
206 if (envstring) controlstring= envstring;
209 ifskiplevel=0; iflevel=0;
211 if (initialstring) add_string(initialstring);
213 char *pcp= strchr(cp,'%');
223 case 'y': geom_force(&wg); add_number(wg.y); break;
224 case 'Y': geom_force(&rg); add_scaled(wg.y,rg.h-wg.h+1); break;
225 case 'x': geom_force(&wg); add_number(wg.x); break;
226 case 'X': geom_force(&rg); add_scaled(wg.x,rg.w-wg.w+1); break;
228 case 'X': case 'Y': add_scaled(INT_MAX,0); /* skip scaled parameter */
229 case 'x': case 'y': break;
230 #endif /* !NOXWINDOWS */
231 case 'd': add_currentdir(); break;
232 case 'G': add_string(group_name()); break;
233 case 'g': gid_force(); add_number((long)gid); break;
234 case 'U': add_string(user_name()); break;
235 case 'u': uid_force(); add_number((long)uid); break;
236 case 'n': add_number(nice(0)); break;
237 case 'N': add_scaled(nice(0)+20,40); break;
238 case 'm': add_string(ltoaoct((long)umsk)); break;
239 case 'M': add_umask(umsk); break;
240 case 'E': add_envir(); break;
242 if (!gethostname(smallbuffer,SMALLBUFMAX)) {
244 p=strchr(smallbuffer,'.');
247 add_string(smallbuffer);
251 if (iflevel>0) iflevel--;
252 if (ifskiplevel>0) ifskiplevel--;
254 case '%': add_string("%%"); break;
261 ifskipthis= 0!=getenv(cp);
265 case 'g': gid_force(); ifskipthis= (gid==user_gid()); break;
268 envgroup= envgroup?envgroup: getenv("GROUP");
270 envgroup ? (gid==atol(envgroup) || !strcmp(group_name(),envgroup))
274 envuser= envuser?envuser: getenv("USER");
275 envuser= envuser?envuser: getenv("LOGNAME");
276 ifskipthis= (envuser && user_nameonly() &&
277 !strcmp(envuser,user_nameonly()));
279 case 'n': ifskipthis= (nice(0)==0); break;
281 if (sscanf(cp,"%3o%n",&chkum,&inc)==1) {
283 ifskipthis= umsk==chkum;
285 } /* switch() for if's */
287 ifskiplevel+= ifskiplevel ? 1 : ifskipthis;
289 } /* switch for %'s */
291 if (finalstring) add_string(finalstring);
302 if (e) add_string(e);
309 char *nbp= bp+strlen(ns);
310 if (ifskiplevel || nbp > bp_end) return;
315 void add_number(number)
318 add_string(ltoa(number));
321 void add_scaled(num,denom)
324 char *sd, *sn[MAXSCALED];
328 while (*cp && n<MAXSCALED && *cp!='/') {
329 sn[n++]= scaledstr_chop();
331 if (*cp) cp++; /* skip the '/' */
332 sd= scaledstr_chop();
333 if (num==INT_MAX && denom==0) return;
334 v= denom? (num/(double)denom) : -1;
338 add_string(sn[(int)(v*n)]);
342 char *scaledstr_chop() {
345 char *ep= strchr(cp,tc);
359 if (ifskiplevel) return;
375 void add_currentdir() {
376 char *homestring="", *p, *homedir, *amdhome;
377 int comps=10000, chars, totalslashes, skipslashes, len, homeskip;
378 char *buf, nbuf[PATH_MAX+10], nhome[PATH_MAX+10];
380 amdhome= getenv("HOME_AMDTMP");
381 homedir= getenv("HOME");
383 if (ifskiplevel) return;
384 while (*cp && *cp!='.') {
388 } else if (*cp == 'E') {
389 cwd_setmode(2); cp++;
390 } else if (*cp == 'e') {
391 cwd_setmode(1); cp++;
392 } else if (*cp == '~') {
395 } else if (isdigit(*cp)) {
396 if (sscanf(cp,"%d%n",&comps,&chars)==1) {
404 homedir= user_home();
410 if (homedir[len-1] != '/') {
411 strcpy(nhome, homedir);
416 if (len>1 && !strncmp(buf,homedir,len-1) &&
417 (buf[len-1]=='/' || !(buf[len-1]))) {
418 strcpy(nbuf,homestring);
419 strcat(nbuf,buf+len);
421 if (!strlen(buf)) buf="~";
422 homeskip= strlen(homestring);
427 if (amdhome[len-1] != '/') {
428 strcpy(nhome, amdhome);
433 if (len>1 && !strncmp(buf,amdhome,len-1) &&
434 (buf[len-1]=='/' || !(buf[len-1]))) {
435 strcpy(nbuf,homestring);
436 strcat(nbuf,buf+len);
438 if (!strlen(buf)) buf="~";
439 homeskip= strlen(homestring);
443 for (p= buf+homeskip; *p; p++)
444 if (*p=='/') totalslashes++;
445 while (p>buf && p[-1]=='/') { *--p=0; totalslashes--; }
446 skipslashes= totalslashes-comps+1;
448 for (p= buf+homeskip;
451 if (*p=='/') skipslashes--;
452 if (p==buf+1 || p==buf+homeskip || p==buf+homeskip) p=buf;
459 return pwent? pwent->pw_gid: -1;
462 char *user_nameonly() {
464 return pwent? pwent->pw_name: 0;
469 return pwent? pwent->pw_dir: 0;
474 if (pwent) return(pwent->pw_name);
475 return(ltoa((long)uid));
489 pwent= getpwuid(uid);
494 if (grent) return(grent->gr_name);
495 return(ltoa((long)gid));
503 grent= getgrgid(gid);
512 void cwd_setmode(mode)
515 cwd_mode=mode; /* 0= default, 1= 'e', 2= 'E' */
518 int different_files(a,b)
521 struct stat staa, stab;
523 return stat(a,&staa) || stat(b,&stab) ||
524 staa.st_ino != stab.st_ino || staa.st_dev != stab.st_dev;
528 static int valid=0, fail;
529 static char buffer[PATH_MAX+1];
531 if (cwd_mode!=1 /* not 'e' */) {
532 char *result= getenv("PWD");
533 if (result && (cwd_mode /* 'E' */ || !different_files(".",result))) {
534 strncpy(buffer,result,PATH_MAX); buffer[PATH_MAX]=0;
539 valid= getcwd(buffer,PATH_MAX)!=0;
546 #if (!defined(NOXWINDOWS) || !defined(NOXTERM)) && !defined(NODETACH)
548 close(0); close(1); close(2); if (fork()!=0) exit(0);
550 #endif /* !NODETACH */
556 char *widname, *dispname;
559 window= (XID)0; display= (Display*)0;
560 XSetErrorHandler(X_error_handler);
562 dispname= getenv("DISPLAY");
563 if (!dispname) return;
564 display= XOpenDisplay(dispname);
565 if (!display) return;
567 widname= getenv("WINDOWID");
568 if (!widname) return;
569 window= (XID)(atol(widname));
573 int X_error_handler(edisp,eevent)
577 display= (Display*)0;
579 wg.window= rg.window= window;
580 wg.x= wg.y= rg.x= rg.y= -1000;
591 if (g->valid) return;
593 geom_force(g->child);
594 g->window= g->child->root;
598 XGetGeometry(display,
600 &dummys,&dummys,&g->w,&g->h,
602 XTranslateCoordinates(display,g->window,g->root,0,0,&g->x,&g->y,&dummyw);
609 #endif /* !NOXWINDOWS */