dmenu for lunch applications in dwm
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

650 lines
14 KiB

20 years ago
20 years ago
18 years ago
20 years ago
​
18 years ago
20 years ago
​
​
​
​
​
​
​
​
​
20 years ago
​
​
20 years ago
​
18 years ago
​
18 years ago
​
16 years ago
​
​
18 years ago
​
18 years ago
​
​
​
​
16 years ago
​
​
​
​
​
​
​
18 years ago
​
​
​
​
16 years ago
18 years ago
19 years ago
​
​
​
​
​
19 years ago
20 years ago
​
16 years ago
16 years ago
20 years ago
​
​
​
​
​
​
​
​
​
​
16 years ago
​
​
​
​
​
​
​
​
​
​
19 years ago
​
16 years ago
​
​
​
​
​
​
​
19 years ago
​
16 years ago
19 years ago
​
​
​
​
​
​
​
​
​
​
​
​
​
16 years ago
16 years ago
16 years ago
16 years ago
​
​
​
​
​
16 years ago
16 years ago
​
16 years ago
​
​
​
16 years ago
16 years ago
​
​
​
19 years ago
​
​
​
​
​
​
​
​
​
​
​
​
​
20 years ago
16 years ago
​
​
​
​
​
​
20 years ago
​
​
16 years ago
20 years ago
​
​
20 years ago
​
​
​
​
20 years ago
​
​
​
​
​
16 years ago
​
​
​
​
​
​
​
​
20 years ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
20 years ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
16 years ago
​
​
​
​
​
20 years ago
​
​
​
​
​
​
​
​
​
​
​
​
20 years ago
​
​
​
20 years ago
​
​
​
20 years ago
​
20 years ago
16 years ago
​
​
​
​
​
​
​
​
​
​
20 years ago
​
​
​
​
20 years ago
20 years ago
​
19 years ago
​
19 years ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
19 years ago
​
​
​
​
​
20 years ago
​
​
​
​
16 years ago
20 years ago
20 years ago
​
​
20 years ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
19 years ago
​
19 years ago
​
19 years ago
​
​
​
19 years ago
​
​
​
19 years ago
​
19 years ago
​
​
​
​
19 years ago
​
20 years ago
​
​
​
​
16 years ago
​
16 years ago
​
19 years ago
​
​
20 years ago
16 years ago
​
​
19 years ago
16 years ago
20 years ago
  1. /* See LICENSE file for copyright and license details. */
  2. #include <ctype.h>
  3. #include <locale.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. #include <X11/keysym.h>
  9. #include <X11/Xlib.h>
  10. #include <X11/Xutil.h>
  11. #ifdef XINERAMA
  12. #include <X11/extensions/Xinerama.h>
  13. #endif
  14. #include <draw.h>
  15. #include "config.h"
  16. #define INRECT(x,y,rx,ry,rw,rh) ((rx) < (x) && (x) < (rx)+(rw) && (ry) < (y) && (y) < (ry)+(rh))
  17. #define MIN(a,b) ((a) < (b) ? (a) : (b))
  18. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  19. #define IS_UTF8_1ST_CHAR(c) (((c) & 0xc0) == 0xc0 || ((c) & 0x80) == 0x00)
  20. typedef struct Item Item;
  21. struct Item {
  22. char *text;
  23. Item *next; /* traverses all items */
  24. Item *left, *right; /* traverses items matching current search pattern */
  25. };
  26. static void appenditem(Item *i, Item **list, Item **last);
  27. static void calcoffsetsh(void);
  28. static void calcoffsetsv(void);
  29. static char *cistrstr(const char *s, const char *sub);
  30. static void cleanup(void);
  31. static void drawitem(const char *s, unsigned long col[ColLast]);
  32. static void drawmenu(void);
  33. static void drawmenuh(void);
  34. static void drawmenuv(void);
  35. static void grabkeyboard(void);
  36. static void keypress(XKeyEvent *e);
  37. static void match(void);
  38. static void readstdin(void);
  39. static void run(void);
  40. static void setup(void);
  41. static char **argp = NULL;
  42. static char *maxname = NULL;
  43. static char *prompt;
  44. static char text[4096];
  45. static int promptw;
  46. static int screen;
  47. static size_t cur = 0;
  48. static unsigned int cmdw = 0;
  49. static unsigned int lines = 0;
  50. static unsigned int numlockmask;
  51. static unsigned int mw, mh;
  52. static unsigned long normcol[ColLast];
  53. static unsigned long selcol[ColLast];
  54. static Bool topbar = True;
  55. static DC dc;
  56. static Display *dpy;
  57. static Item *allitems = NULL; /* first of all items */
  58. static Item *item = NULL; /* first of pattern matching items */
  59. static Item *sel = NULL;
  60. static Item *next = NULL;
  61. static Item *prev = NULL;
  62. static Item *curr = NULL;
  63. static Window win, root;
  64. static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
  65. static char *(*fstrstr)(const char *, const char *) = strstr;
  66. static void (*calcoffsets)(void) = calcoffsetsh;
  67. void
  68. appenditem(Item *i, Item **list, Item **last) {
  69. if(!(*last))
  70. *list = i;
  71. else
  72. (*last)->right = i;
  73. i->left = *last;
  74. i->right = NULL;
  75. *last = i;
  76. }
  77. void
  78. calcoffsetsh(void) {
  79. unsigned int w, x;
  80. w = promptw + cmdw + textw(&dc, "<") + textw(&dc, ">");
  81. for(x = w, next = curr; next; next = next->right)
  82. if((x += MIN(textw(&dc, next->text), mw / 3)) > mw)
  83. break;
  84. for(x = w, prev = curr; prev && prev->left; prev = prev->left)
  85. if((x += MIN(textw(&dc, prev->left->text), mw / 3)) > mw)
  86. break;
  87. }
  88. void
  89. calcoffsetsv(void) {
  90. unsigned int i;
  91. next = prev = curr;
  92. for(i = 0; i < lines && next; i++)
  93. next = next->right;
  94. mh = (dc.font.height + 2) * (i + 1);
  95. for(i = 0; i < lines && prev && prev->left; i++)
  96. prev = prev->left;
  97. }
  98. char *
  99. cistrstr(const char *s, const char *sub) {
  100. int c, csub;
  101. unsigned int len;
  102. if(!sub)
  103. return (char *)s;
  104. if((c = tolower(*sub++)) != '\0') {
  105. len = strlen(sub);
  106. do {
  107. do {
  108. if((csub = *s++) == '\0')
  109. return NULL;
  110. }
  111. while(tolower(csub) != c);
  112. }
  113. while(strncasecmp(s, sub, len) != 0);
  114. s--;
  115. }
  116. return (char *)s;
  117. }
  118. void
  119. cleanup(void) {
  120. Item *itm;
  121. while(allitems) {
  122. itm = allitems->next;
  123. free(allitems->text);
  124. free(allitems);
  125. allitems = itm;
  126. }
  127. cleanupdraw(&dc);
  128. XDestroyWindow(dpy, win);
  129. XUngrabKeyboard(dpy, CurrentTime);
  130. XCloseDisplay(dpy);
  131. }
  132. void
  133. drawitem(const char *s, unsigned long col[ColLast]) {
  134. const char *p;
  135. unsigned int w = textnw(&dc, text, strlen(text));
  136. drawbox(&dc, col);
  137. drawtext(&dc, s, col);
  138. for(p = fstrstr(s, text); *text && (p = fstrstr(p, text)); p++)
  139. drawline(&dc, textnw(&dc, s, p-s) + dc.h/2 - 1, dc.h-2, w, 1, col);
  140. }
  141. void
  142. drawmenu(void) {
  143. dc.x = 0;
  144. dc.y = 0;
  145. dc.w = mw;
  146. dc.h = mh;
  147. drawbox(&dc, normcol);
  148. dc.h = dc.font.height + 2;
  149. dc.y = topbar ? 0 : mh - dc.h;
  150. /* print prompt? */
  151. if(prompt) {
  152. dc.w = promptw;
  153. drawbox(&dc, selcol);
  154. drawtext(&dc, prompt, selcol);
  155. dc.x += dc.w;
  156. }
  157. dc.w = mw - dc.x;
  158. /* print command */
  159. if(cmdw && item && lines == 0)
  160. dc.w = cmdw;
  161. drawtext(&dc, text, normcol);
  162. drawline(&dc, textnw(&dc, text, cur) + dc.h/2 - 2, 2, 1, dc.h-4, normcol);
  163. if(lines > 0)
  164. drawmenuv();
  165. else if(curr)
  166. drawmenuh();
  167. commitdraw(&dc, win);
  168. }
  169. void
  170. drawmenuh(void) {
  171. Item *i;
  172. dc.x += cmdw;
  173. dc.w = textw(&dc, "<");
  174. drawtext(&dc, curr->left ? "<" : NULL, normcol);
  175. dc.x += dc.w;
  176. for(i = curr; i != next; i = i->right) {
  177. dc.w = MIN(textw(&dc, i->text), mw / 3);
  178. drawitem(i->text, (sel == i) ? selcol : normcol);
  179. dc.x += dc.w;
  180. }
  181. dc.w = textw(&dc, ">");
  182. dc.x = mw - dc.w;
  183. drawtext(&dc, next ? ">" : NULL, normcol);
  184. }
  185. void
  186. drawmenuv(void) {
  187. Item *i;
  188. XWindowAttributes wa;
  189. dc.y = topbar ? dc.h : 0;
  190. dc.w = mw - dc.x;
  191. for(i = curr; i != next; i = i->right) {
  192. drawitem(i->text, (sel == i) ? selcol : normcol);
  193. dc.y += dc.h;
  194. }
  195. if(!XGetWindowAttributes(dpy, win, &wa))
  196. eprint("cannot get window attributes");
  197. XMoveResizeWindow(dpy, win, wa.x, wa.y + (topbar ? 0 : wa.height - mh), mw, mh);
  198. }
  199. void
  200. grabkeyboard(void) {
  201. unsigned int n;
  202. for(n = 0; n < 1000; n++) {
  203. if(!XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime))
  204. return;
  205. usleep(1000);
  206. }
  207. exit(EXIT_FAILURE);
  208. }
  209. void
  210. keypress(XKeyEvent *e) {
  211. char buf[sizeof text];
  212. int num;
  213. unsigned int i, len;
  214. KeySym ksym;
  215. len = strlen(text);
  216. num = XLookupString(e, buf, sizeof buf, &ksym, NULL);
  217. if(ksym == XK_KP_Enter)
  218. ksym = XK_Return;
  219. else if(ksym >= XK_KP_0 && ksym <= XK_KP_9)
  220. ksym = (ksym - XK_KP_0) + XK_0;
  221. else if(IsFunctionKey(ksym) || IsKeypadKey(ksym)
  222. || IsMiscFunctionKey(ksym) || IsPFKey(ksym)
  223. || IsPrivateKeypadKey(ksym))
  224. return;
  225. /* first check if a control mask is omitted */
  226. if(e->state & ControlMask) {
  227. switch(tolower(ksym)) {
  228. default:
  229. return;
  230. case XK_a:
  231. ksym = XK_Home;
  232. break;
  233. case XK_b:
  234. ksym = XK_Left;
  235. break;
  236. case XK_c:
  237. ksym = XK_Escape;
  238. break;
  239. case XK_e:
  240. ksym = XK_End;
  241. break;
  242. case XK_f:
  243. ksym = XK_Right;
  244. break;
  245. case XK_h:
  246. ksym = XK_BackSpace;
  247. break;
  248. case XK_i:
  249. ksym = XK_Tab;
  250. break;
  251. case XK_j:
  252. case XK_m:
  253. ksym = XK_Return;
  254. break;
  255. case XK_k:
  256. text[cur] = '\0';
  257. break;
  258. case XK_n:
  259. ksym = XK_Down;
  260. break;
  261. case XK_p:
  262. ksym = XK_Up;
  263. break;
  264. case XK_u:
  265. memmove(text, text + cur, sizeof text - cur + 1);
  266. cur = 0;
  267. match();
  268. break;
  269. case XK_w:
  270. if(cur == 0)
  271. return;
  272. i = cur;
  273. while(i-- > 0 && text[i] == ' ');
  274. while(i-- > 0 && text[i] != ' ');
  275. memmove(text + i + 1, text + cur, sizeof text - cur + 1);
  276. cur = i + 1;
  277. match();
  278. break;
  279. case XK_y:
  280. {
  281. FILE *fp;
  282. char *s;
  283. if(!(fp = fopen("sselp", "r")))
  284. eprint("cannot popen sselp\n");
  285. s = fgets(buf, sizeof buf, fp);
  286. fclose(fp);
  287. if(!s)
  288. return;
  289. }
  290. num = strlen(buf);
  291. if(num && buf[num-1] == '\n')
  292. buf[--num] = '\0';
  293. break;
  294. }
  295. }
  296. switch(ksym) {
  297. default:
  298. num = MIN(num, sizeof text);
  299. if(num && !iscntrl((int) buf[0])) {
  300. memmove(text + cur + num, text + cur, sizeof text - cur - num);
  301. memcpy(text + cur, buf, num);
  302. cur += num;
  303. match();
  304. }
  305. break;
  306. case XK_BackSpace:
  307. if(cur == 0)
  308. return;
  309. for(i = 1; len - i > 0 && !IS_UTF8_1ST_CHAR(text[cur - i]); i++);
  310. memmove(text + cur - i, text + cur, sizeof text - cur + i);
  311. cur -= i;
  312. match();
  313. break;
  314. case XK_Delete:
  315. if(cur == len)
  316. return;
  317. for(i = 1; cur + i < len && !IS_UTF8_1ST_CHAR(text[cur + i]); i++);
  318. memmove(text + cur, text + cur + i, sizeof text - cur);
  319. match();
  320. break;
  321. case XK_End:
  322. if(cur < len) {
  323. cur = len;
  324. break;
  325. }
  326. while(next) {
  327. sel = curr = next;
  328. calcoffsets();
  329. }
  330. while(sel && sel->right)
  331. sel = sel->right;
  332. break;
  333. case XK_Escape:
  334. exit(EXIT_FAILURE);
  335. case XK_Home:
  336. if(sel == item) {
  337. cur = 0;
  338. break;
  339. }
  340. sel = curr = item;
  341. calcoffsets();
  342. break;
  343. case XK_Left:
  344. if(cur > 0 && (!sel || !sel->left || lines > 0)) {
  345. while(cur-- > 0 && !IS_UTF8_1ST_CHAR(text[cur]));
  346. break;
  347. }
  348. if(lines > 0)
  349. return;
  350. case XK_Up:
  351. if(!sel || !sel->left)
  352. return;
  353. sel = sel->left;
  354. if(sel->right == curr) {
  355. curr = prev;
  356. calcoffsets();
  357. }
  358. break;
  359. case XK_Next:
  360. if(!next)
  361. return;
  362. sel = curr = next;
  363. calcoffsets();
  364. break;
  365. case XK_Prior:
  366. if(!prev)
  367. return;
  368. sel = curr = prev;
  369. calcoffsets();
  370. break;
  371. case XK_Return:
  372. fprintf(stdout, "%s", ((e->state & ShiftMask) || sel) ? sel->text : text);
  373. fflush(stdout);
  374. exit(EXIT_SUCCESS);
  375. case XK_Right:
  376. if(cur < len) {
  377. while(cur++ < len && !IS_UTF8_1ST_CHAR(text[cur]));
  378. break;
  379. }
  380. if(lines > 0)
  381. return;
  382. case XK_Down:
  383. if(!sel || !sel->right)
  384. return;
  385. sel = sel->right;
  386. if(sel == next) {
  387. curr = next;
  388. calcoffsets();
  389. }
  390. break;
  391. case XK_Tab:
  392. if(!sel)
  393. return;
  394. strncpy(text, sel->text, sizeof text);
  395. cur = strlen(text);
  396. match();
  397. break;
  398. }
  399. drawmenu();
  400. }
  401. void
  402. match(void) {
  403. unsigned int len;
  404. Item *i, *itemend, *lexact, *lprefix, *lsubstr, *exactend, *prefixend, *substrend;
  405. len = strlen(text);
  406. item = lexact = lprefix = lsubstr = itemend = exactend = prefixend = substrend = NULL;
  407. for(i = allitems; i; i = i->next)
  408. if(!fstrncmp(text, i->text, len + 1))
  409. appenditem(i, &lexact, &exactend);
  410. else if(!fstrncmp(text, i->text, len))
  411. appenditem(i, &lprefix, &prefixend);
  412. else if(fstrstr(i->text, text))
  413. appenditem(i, &lsubstr, &substrend);
  414. if(lexact) {
  415. item = lexact;
  416. itemend = exactend;
  417. }
  418. if(lprefix) {
  419. if(itemend) {
  420. itemend->right = lprefix;
  421. lprefix->left = itemend;
  422. }
  423. else
  424. item = lprefix;
  425. itemend = prefixend;
  426. }
  427. if(lsubstr) {
  428. if(itemend) {
  429. itemend->right = lsubstr;
  430. lsubstr->left = itemend;
  431. }
  432. else
  433. item = lsubstr;
  434. }
  435. curr = prev = next = sel = item;
  436. calcoffsets();
  437. }
  438. void
  439. readstdin(void) {
  440. char *p, buf[sizeof text];
  441. unsigned int len = 0, max = 0;
  442. Item *i, *new;
  443. i = NULL;
  444. while(fgets(buf, sizeof buf, stdin)) {
  445. len = strlen(buf);
  446. if(buf[len-1] == '\n')
  447. buf[--len] = '\0';
  448. if(!(p = strdup(buf)))
  449. eprint("cannot strdup %u bytes\n", len);
  450. if((max = MAX(max, len)) == len)
  451. maxname = p;
  452. if(!(new = malloc(sizeof *new)))
  453. eprint("cannot malloc %u bytes\n", sizeof *new);
  454. new->next = new->left = new->right = NULL;
  455. new->text = p;
  456. if(!i)
  457. allitems = new;
  458. else
  459. i->next = new;
  460. i = new;
  461. }
  462. }
  463. void
  464. run(void) {
  465. XEvent ev;
  466. XSync(dpy, False);
  467. while(!XNextEvent(dpy, &ev))
  468. switch(ev.type) {
  469. case Expose:
  470. if(ev.xexpose.count == 0)
  471. drawmenu();
  472. break;
  473. case KeyPress:
  474. keypress(&ev.xkey);
  475. break;
  476. case VisibilityNotify:
  477. if(ev.xvisibility.state != VisibilityUnobscured)
  478. XRaiseWindow(dpy, win);
  479. break;
  480. }
  481. exit(EXIT_FAILURE);
  482. }
  483. void
  484. setup(void) {
  485. int i, j, x, y;
  486. #if XINERAMA
  487. int n;
  488. XineramaScreenInfo *info = NULL;
  489. #endif
  490. XModifierKeymap *modmap;
  491. XSetWindowAttributes wa;
  492. /* init modifier map */
  493. modmap = XGetModifierMapping(dpy);
  494. for(i = 0; i < 8; i++)
  495. for(j = 0; j < modmap->max_keypermod; j++) {
  496. if(modmap->modifiermap[i * modmap->max_keypermod + j]
  497. == XKeysymToKeycode(dpy, XK_Num_Lock))
  498. numlockmask = (1 << i);
  499. }
  500. XFreeModifiermap(modmap);
  501. dc.dpy = dpy;
  502. normcol[ColBG] = getcolor(&dc, normbgcolor);
  503. normcol[ColFG] = getcolor(&dc, normfgcolor);
  504. selcol[ColBG] = getcolor(&dc, selbgcolor);
  505. selcol[ColFG] = getcolor(&dc, selfgcolor);
  506. initfont(&dc, font);
  507. /* input window */
  508. wa.override_redirect = True;
  509. wa.background_pixmap = ParentRelative;
  510. wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
  511. /* input window geometry */
  512. mh = (dc.font.height + 2) * (lines + 1);
  513. #if XINERAMA
  514. if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) {
  515. i = 0;
  516. if(n > 1) {
  517. int di;
  518. unsigned int dui;
  519. Window dummy;
  520. if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui))
  521. for(i = 0; i < n; i++)
  522. if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height))
  523. break;
  524. }
  525. x = info[i].x_org;
  526. y = topbar ? info[i].y_org : info[i].y_org + info[i].height - mh;
  527. mw = info[i].width;
  528. XFree(info);
  529. }
  530. else
  531. #endif
  532. {
  533. x = 0;
  534. y = topbar ? 0 : DisplayHeight(dpy, screen) - mh;
  535. mw = DisplayWidth(dpy, screen);
  536. }
  537. win = XCreateWindow(dpy, root, x, y, mw, mh, 0,
  538. DefaultDepth(dpy, screen), CopyFromParent,
  539. DefaultVisual(dpy, screen),
  540. CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
  541. setupdraw(&dc, win);
  542. if(prompt)
  543. promptw = MIN(textw(&dc, prompt), mw / 5);
  544. XMapRaised(dpy, win);
  545. }
  546. int
  547. main(int argc, char *argv[]) {
  548. unsigned int i;
  549. /* command line args */
  550. progname = "dmenu";
  551. for(i = 1; i < argc; i++)
  552. if(!strcmp(argv[i], "-i")) {
  553. fstrncmp = strncasecmp;
  554. fstrstr = cistrstr;
  555. }
  556. else if(!strcmp(argv[i], "-b"))
  557. topbar = False;
  558. else if(!strcmp(argv[i], "-l")) {
  559. if(++i < argc) lines = atoi(argv[i]);
  560. if(lines > 0)
  561. calcoffsets = calcoffsetsv;
  562. }
  563. else if(!strcmp(argv[i], "-fn")) {
  564. if(++i < argc) font = argv[i];
  565. }
  566. else if(!strcmp(argv[i], "-nb")) {
  567. if(++i < argc) normbgcolor = argv[i];
  568. }
  569. else if(!strcmp(argv[i], "-nf")) {
  570. if(++i < argc) normfgcolor = argv[i];
  571. }
  572. else if(!strcmp(argv[i], "-p")) {
  573. if(++i < argc) prompt = argv[i];
  574. }
  575. else if(!strcmp(argv[i], "-sb")) {
  576. if(++i < argc) selbgcolor = argv[i];
  577. }
  578. else if(!strcmp(argv[i], "-sf")) {
  579. if(++i < argc) selfgcolor = argv[i];
  580. }
  581. else if(!strcmp(argv[i], "-v")) {
  582. printf("dmenu-"VERSION", © 2006-2010 dmenu engineers, see LICENSE for details\n");
  583. exit(EXIT_SUCCESS);
  584. }
  585. else {
  586. fputs("usage: dmenu [-i] [-b] [-l <lines>] [-fn <font>] [-nb <color>]\n"
  587. " [-nf <color>] [-p <prompt>] [-sb <color>] [-sf <color>] [-v]\n", stderr);
  588. exit(EXIT_FAILURE);
  589. }
  590. if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
  591. fprintf(stderr, "dmenu: warning: no locale support\n");
  592. if(!(dpy = XOpenDisplay(NULL)))
  593. eprint("cannot open display\n");
  594. if(atexit(&cleanup) != 0)
  595. eprint("cannot register cleanup\n");
  596. screen = DefaultScreen(dpy);
  597. root = RootWindow(dpy, screen);
  598. if(!(argp = malloc(sizeof *argp * (argc+2))))
  599. eprint("cannot malloc %u bytes\n", sizeof *argp * (argc+2));
  600. memcpy(argp + 2, argv + 1, sizeof *argp * argc);
  601. readstdin();
  602. grabkeyboard();
  603. setup();
  604. if(maxname)
  605. cmdw = MIN(textw(&dc, maxname), mw / 3);
  606. match();
  607. run();
  608. return 0;
  609. }