termcap.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. /*
  2. * termcap.c 1.1 20/7/87 agc Joypace Ltd
  3. *
  4. * Copyright Joypace Ltd, London, UK, 1987. All rights reserved.
  5. * This file may be freely distributed provided that this notice
  6. * remains attached.
  7. *
  8. * A public domain implementation of the termcap(3) routines.
  9. *
  10. * Made fully functional by Ceriel J.H. Jacobs.
  11. *
  12. * BUGS:
  13. * - does not check termcap entry sizes
  14. * - not fully tested
  15. */
  16. #include <stdio.h>
  17. #define CAPABLEN 2
  18. #define ISSPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
  19. #define ISDIGIT(x) ((x) >= '0' && (x) <= '9')
  20. short ospeed; /* output speed */
  21. char PC; /* padding character */
  22. char *BC; /* back cursor movement */
  23. char *UP; /* up cursor movement */
  24. static char *capab; /* the capability itself */
  25. static int check_for_tc();
  26. static int match_name();
  27. extern char *getenv(); /* new, improved getenv */
  28. extern FILE *fopen(); /* old fopen */
  29. /*
  30. * tgetent - get the termcap entry for terminal name, and put it
  31. * in bp (which must be an array of 1024 chars). Returns 1 if
  32. * termcap entry found, 0 if not found, and -1 if file not found.
  33. */
  34. int
  35. tgetent(bp, name)
  36. char *bp;
  37. char *name;
  38. {
  39. FILE *fp;
  40. char *file;
  41. char *cp;
  42. short len = strlen(name);
  43. char buf[1024];
  44. capab = bp;
  45. if ((file = getenv("TERMCAP")) != (char *) NULL) {
  46. if (*file != '/' &&
  47. (cp = getenv("TERM")) != NULL && strcmp(name, cp) == 0) {
  48. (void) strcpy(bp, file);
  49. return(1);
  50. }
  51. else file = "/etc/termcap";
  52. } else
  53. file = "/etc/termcap";
  54. if ((fp = fopen(file, "r")) == (FILE *) NULL)
  55. return(-1);
  56. while (fgets(buf, 1024, fp) != NULL) {
  57. if (buf[0] == '#') continue;
  58. while (*(cp = &buf[strlen(buf) - 2]) == '\\')
  59. if (fgets(cp, 1024, fp) == NULL)
  60. return (0);
  61. if (match_name(buf, name)) {
  62. strcpy(bp, buf);
  63. fclose(fp);
  64. return(check_for_tc());
  65. }
  66. }
  67. fclose(fp);
  68. return(0);
  69. }
  70. /*
  71. * Compare the terminal name with each termcap entry name; Return 1 if a
  72. * match is found.
  73. */
  74. static int
  75. match_name(buf, name)
  76. char *buf;
  77. char *name;
  78. {
  79. register char *tp = buf;
  80. register char *np;
  81. for (;;) {
  82. for (np = name; *np && *tp == *np; np++, tp++) { }
  83. if (*np == 0 && (*tp == '|' || *tp == ':' || *tp == 0))
  84. return(1);
  85. while (*tp != 0 && *tp != '|' && *tp != ':') tp++;
  86. if (*tp++ != '|') return (0);
  87. }
  88. }
  89. /*
  90. * Handle tc= definitions recursively.
  91. */
  92. static int
  93. check_for_tc()
  94. {
  95. static int count = 0;
  96. char *savcapab = capab;
  97. char buf[1024];
  98. char terminalname[128];
  99. register char *p = capab + strlen(capab) - 2, *q;
  100. while (*p != ':')
  101. if (--p < capab)
  102. return(0); /* no : in termcap entry */
  103. if (p[1] != 't' || p[2] != 'c')
  104. return(1);
  105. if (count > 16) return(0); /* recursion in tc= definitions */
  106. count++;
  107. strcpy(terminalname, &p[4]);
  108. q = terminalname;
  109. while (*q && *q != ':') q++;
  110. *q = 0;
  111. if (tgetent(buf, terminalname) != 1) {
  112. --count;
  113. return(0);
  114. }
  115. --count;
  116. for (q = buf; *q && *q != ':'; q++) { }
  117. strcpy(p, q);
  118. capab = savcapab;
  119. return(1);
  120. }
  121. /*
  122. * tgetnum - get the numeric terminal capability corresponding
  123. * to id. Returns the value, -1 if invalid.
  124. */
  125. int
  126. tgetnum(id)
  127. char *id;
  128. {
  129. char *cp;
  130. int ret;
  131. if ((cp = capab) == NULL || id == NULL)
  132. return(-1);
  133. while (*++cp != ':')
  134. ;
  135. while (*cp) {
  136. cp++;
  137. while (ISSPACE(*cp))
  138. cp++;
  139. if (strncmp(cp, id, CAPABLEN) == 0) {
  140. while (*cp && *cp != ':' && *cp != '#')
  141. cp++;
  142. if (*cp != '#')
  143. return(-1);
  144. for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++)
  145. ret = ret * 10 + *cp - '0';
  146. return(ret);
  147. }
  148. while (*cp && *cp != ':')
  149. cp++;
  150. }
  151. return(-1);
  152. }
  153. /*
  154. * tgetflag - get the boolean flag corresponding to id. Returns -1
  155. * if invalid, 0 if the flag is not in termcap entry, or 1 if it is
  156. * present.
  157. */
  158. int
  159. tgetflag(id)
  160. char *id;
  161. {
  162. char *cp;
  163. if ((cp = capab) == NULL || id == NULL)
  164. return(-1);
  165. while (*++cp != ':')
  166. ;
  167. while (*cp) {
  168. cp++;
  169. while (ISSPACE(*cp))
  170. cp++;
  171. if (strncmp(cp, id, CAPABLEN) == 0)
  172. return(1);
  173. while (*cp && *cp != ':')
  174. cp++;
  175. }
  176. return(0);
  177. }
  178. /*
  179. * tgetstr - get the string capability corresponding to id and place
  180. * it in area (advancing area at same time). Expand escape sequences
  181. * etc. Returns the string, or NULL if it can't do it.
  182. */
  183. char *
  184. tgetstr(id, area)
  185. char *id;
  186. char **area;
  187. {
  188. char *cp;
  189. char *ret;
  190. int i;
  191. if ((cp = capab) == NULL || id == NULL)
  192. return(NULL);
  193. while (*++cp != ':')
  194. ;
  195. while (*cp) {
  196. cp++;
  197. while (ISSPACE(*cp))
  198. cp++;
  199. if (strncmp(cp, id, CAPABLEN) == 0) {
  200. while (*cp && *cp != ':' && *cp != '=')
  201. cp++;
  202. if (*cp != '=')
  203. return(NULL);
  204. for (ret = *area, cp++; *cp && *cp != ':' ; (*area)++, cp++)
  205. switch(*cp) {
  206. case '^' :
  207. **area = *++cp - 'A' + 1;
  208. break;
  209. case '\\' :
  210. switch(*++cp) {
  211. case 'E' :
  212. **area = '\033';
  213. break;
  214. case 'n' :
  215. **area = '\n';
  216. break;
  217. case 'r' :
  218. **area = '\r';
  219. break;
  220. case 't' :
  221. **area = '\t';
  222. break;
  223. case 'b' :
  224. **area = '\b';
  225. break;
  226. case 'f' :
  227. **area = '\f';
  228. break;
  229. case '0' :
  230. case '1' :
  231. case '2' :
  232. case '3' :
  233. for (i=0 ; *cp && ISDIGIT(*cp) ; cp++)
  234. i = i * 8 + *cp - '0';
  235. **area = i;
  236. cp--;
  237. break;
  238. case '^' :
  239. case '\\' :
  240. **area = *cp;
  241. break;
  242. }
  243. break;
  244. default :
  245. **area = *cp;
  246. }
  247. *(*area)++ = '\0';
  248. return(ret);
  249. }
  250. while (*cp && *cp != ':')
  251. cp++;
  252. }
  253. return(NULL);
  254. }
  255. /*
  256. * tgoto - given the cursor motion string cm, make up the string
  257. * for the cursor to go to (destcol, destline), and return the string.
  258. * Returns "OOPS" if something's gone wrong, or the string otherwise.
  259. */
  260. char *
  261. tgoto(cm, destcol, destline)
  262. char *cm;
  263. int destcol;
  264. int destline;
  265. {
  266. register char *rp;
  267. static char ret[24];
  268. char added[16];
  269. int *dp = &destline;
  270. int numval;
  271. int swapped = 0;
  272. added[0] = 0;
  273. for (rp = ret ; *cm ; cm++) {
  274. if (*cm == '%') {
  275. switch(*++cm) {
  276. case '>' :
  277. if (dp == NULL)
  278. return("OOPS");
  279. cm++;
  280. if (*dp > *cm++) {
  281. *dp += *cm;
  282. }
  283. break;
  284. case '+' :
  285. case '.' :
  286. if (dp == NULL)
  287. return("OOPS");
  288. if (*cm == '+') *dp = *dp + *++cm;
  289. for (;;) {
  290. switch(*dp) {
  291. case 0:
  292. case 04:
  293. case '\t':
  294. case '\n':
  295. /* filter these out */
  296. if (dp == &destcol || swapped || UP) {
  297. strcat(added, dp == &destcol || swapped ?
  298. (BC ? BC : "\b") :
  299. UP);
  300. (*dp)++;
  301. continue;
  302. }
  303. }
  304. break;
  305. }
  306. *rp++ = *dp;
  307. dp = (dp == &destline) ? &destcol : NULL;
  308. break;
  309. case 'r' : {
  310. int tmp = destline;
  311. destline = destcol;
  312. destcol = tmp;
  313. swapped = 1 - swapped;
  314. break;
  315. }
  316. case 'n' :
  317. destcol ^= 0140;
  318. destline ^= 0140;
  319. break;
  320. case '%' :
  321. *rp++ = '%';
  322. break;
  323. case 'i' :
  324. destcol++;
  325. destline++;
  326. break;
  327. case 'B' :
  328. if (dp == NULL)
  329. return("OOPS");
  330. *dp = 16 * (*dp / 10) + *dp % 10;
  331. break;
  332. case 'D' :
  333. if (dp == NULL)
  334. return("OOPS");
  335. *dp = *dp - 2 * (*dp % 16);
  336. break;
  337. case 'd' :
  338. case '2' :
  339. case '3' :
  340. if (dp == NULL)
  341. return("OOPS");
  342. numval = *dp;
  343. dp = (dp == &destline) ? &destcol : NULL;
  344. if (numval >= 100) {
  345. *rp++ = '0' + numval / 100;
  346. }
  347. else if (*cm == '3') {
  348. *rp++ = ' ';
  349. }
  350. if (numval >= 10) {
  351. *rp++ = '0' + ((numval%100)/10);
  352. }
  353. else if (*cm == '3' || *cm == '2') {
  354. *rp++ = ' ';
  355. }
  356. *rp++ = '0' + (numval%10);
  357. break;
  358. default :
  359. return("OOPS");
  360. }
  361. }
  362. else *rp++ = *cm;
  363. }
  364. *rp = '\0';
  365. strcpy(rp, added);
  366. return(ret);
  367. }
  368. static int tens_of_ms_p_char[] = { /* index as returned by gtty */
  369. /* assume 10 bits per char */
  370. 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 2
  371. };
  372. /*
  373. * tputs - put the string cp out onto the terminal, using the function
  374. * outc. Also handle padding.
  375. */
  376. int
  377. tputs(cp, affcnt, outc)
  378. register char *cp;
  379. int affcnt;
  380. int (*outc)();
  381. {
  382. int delay = 0;
  383. if (cp == NULL)
  384. return(1);
  385. while (ISDIGIT(*cp)) {
  386. delay = delay * 10 + (*cp++ - '0');
  387. }
  388. delay *= 10;
  389. if (*cp == '.') {
  390. cp++;
  391. if (ISDIGIT(*cp)) {
  392. delay += *cp++ - '0';
  393. }
  394. while (ISDIGIT(*cp)) cp++;
  395. }
  396. if (*cp == '*') {
  397. delay *= affcnt;
  398. cp++;
  399. }
  400. while (*cp)
  401. (*outc)(*cp++);
  402. if (delay != 0 &&
  403. ospeed > 0 &&
  404. ospeed < (sizeof tens_of_ms_p_char / sizeof tens_of_ms_p_char[0])) {
  405. delay = (delay + tens_of_ms_p_char[ospeed] - 1) /
  406. tens_of_ms_p_char[ospeed];
  407. while (delay--) (*outc)(PC);
  408. }
  409. return(1);
  410. }
  411. /*
  412. * That's all, folks...
  413. */