ttysize.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2018 K. Lange
  5. *
  6. * ttysize - Magically divine terminal size
  7. *
  8. * This is called by getty to determine the size of foreign
  9. * terminals, such as ones attached over serial.
  10. *
  11. * It works by placing the cursor in the lower right of the
  12. * screen and requesting its position. Note that typing things
  13. * while this happens can cause problems. Maybe we can flush
  14. * stdin before doing this to try to avoid any conflicting data?
  15. */
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <getopt.h>
  20. #include <unistd.h>
  21. #include <sys/ioctl.h>
  22. #include <sys/fswait.h>
  23. static struct termios old;
  24. static void set_unbuffered() {
  25. tcgetattr(fileno(stdin), &old);
  26. struct termios new = old;
  27. new.c_lflag &= (~ICANON & ~ECHO);
  28. tcsetattr(fileno(stdin), TCSAFLUSH, &new);
  29. }
  30. static void set_buffered() {
  31. tcsetattr(fileno(stdin), TCSAFLUSH, &old);
  32. }
  33. static int getc_timeout(FILE * f, int timeout) {
  34. int fds[1] = {fileno(f)};
  35. int index = fswait2(1,fds,timeout);
  36. if (index == 0) {
  37. return fgetc(f);
  38. } else {
  39. return -1;
  40. }
  41. }
  42. static void divine_size(int * width, int * height) {
  43. set_unbuffered();
  44. *width = 80;
  45. *height = 24;
  46. fprintf(stderr, "\033[s\033[1000;1000H\033[6n\033[u");
  47. fflush(stderr);
  48. char buf[1024] = {0};
  49. size_t i = 0;
  50. while (1) {
  51. char c = getc_timeout(stdin, 200);
  52. if (c == 'R') break;
  53. if (c == -1) goto _done;
  54. if (c == '\033') continue;
  55. if (c == '[') continue;
  56. buf[i++] = c;
  57. }
  58. char * s = strstr(buf, ";");
  59. if (s) {
  60. *(s++) = '\0';
  61. *height = atoi(buf);
  62. *width = atoi(s);
  63. }
  64. _done:
  65. fflush(stderr);
  66. set_buffered();
  67. }
  68. int main(int argc, char * argv[]) {
  69. int width, height;
  70. int opt;
  71. int quiet = 0;
  72. while ((opt = getopt(argc, argv, "q")) != -1) {
  73. switch (opt) {
  74. case 'q':
  75. quiet = 1;
  76. break;
  77. }
  78. }
  79. if (optind + 2 == argc) {
  80. width = atoi(argv[optind]);
  81. height = atoi(argv[optind+1]);
  82. } else {
  83. divine_size(&width, &height);
  84. }
  85. struct winsize w;
  86. w.ws_col = width;
  87. w.ws_row = height;
  88. w.ws_xpixel = 0;
  89. w.ws_ypixel = 0;
  90. ioctl(0, TIOCSWINSZ, &w);
  91. if (!quiet) {
  92. fprintf(stderr, "%dx%d\n", width, height);
  93. }
  94. return 0;
  95. }