termcap.c 8.4 KB

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