hebraize

rewrite terminal contents in hebrew
git clone https://a3nm.net/git/hebraize/
Log | Files | Refs | README

hebraize.c (16496B)


      1 /*
      2  * Copyright (c) 1980 Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 /* 2012-11-17 Antoine Amarilli <a3nm@a3nm.net>
     35  * created from ttyrec
     36  */
     37 
     38 /*
     39  * script
     40  */
     41 #include <sys/types.h>
     42 #include <sys/stat.h>
     43 #include <termios.h>
     44 #include <sys/ioctl.h>
     45 #include <sys/time.h>
     46 #include <sys/file.h>
     47 #include <sys/signal.h>
     48 #include <stdio.h>
     49 #include <time.h>
     50 #include <unistd.h>
     51 #include <string.h>
     52 #include <stdlib.h>
     53 
     54 #if defined(SVR4)
     55 #include <fcntl.h>
     56 #endif /* SVR4 */
     57 
     58 #include <sys/time.h>
     59 
     60 #define HAVE_inet_aton
     61 #define HAVE_scsi_h
     62 #define HAVE_kd_h
     63 
     64 #define _(FOO) FOO
     65 
     66 #ifdef HAVE_openpty
     67 #include <libutil.h>
     68 #endif
     69 
     70 #if defined(SVR4) && !defined(CDEL)
     71 #if defined(_POSIX_VDISABLE)
     72 #define CDEL _POSIX_VDISABLE
     73 #elif defined(CDISABLE)
     74 #define CDEL CDISABLE
     75 #else /* not _POSIX_VISIBLE && not CDISABLE */
     76 #define CDEL 255
     77 #endif /* not _POSIX_VISIBLE && not CDISABLE */
     78 #endif /* SVR4 && ! CDEL */
     79 
     80 void done(void);
     81 void fail(void);
     82 void fixtty(void);
     83 void getmaster(void);
     84 void getslave(void);
     85 void doinput(void);
     86 void dooutput(void);
     87 void doshell(const char*);
     88 void spawnshell();
     89 
     90 char	*shell;
     91 int	master;
     92 int	slave;
     93 int	child;
     94 int	subchild;
     95 int     freq;
     96 
     97 struct	termios tt;
     98 struct	winsize win;
     99 int	lb;
    100 int	l;
    101 #if !defined(SVR4)
    102 #ifndef HAVE_openpty
    103 char	line[] = "/dev/ptyXX";
    104 #endif
    105 #endif /* !SVR4 */
    106 int	aflg;
    107 int	force;
    108 int	limit;
    109 char *command = NULL;
    110 
    111 static void
    112 resize(int dummy) {
    113 	/* transmit window change information to the child */
    114 	(void) ioctl(0, TIOCGWINSZ, (char *)&win);
    115 	(void) ioctl(master, TIOCSWINSZ, (char *)&win);
    116 }
    117 
    118 int
    119 main(argc, argv)
    120 	int argc;
    121 	char *argv[];
    122 {
    123 	struct sigaction sa;
    124 	extern int optind;
    125 	int ch;
    126 	void finish();
    127 	char *getenv();
    128 
    129         freq = 1;
    130 
    131 	while ((ch = getopt(argc, argv, "f:h?")) != EOF)
    132 		switch((char)ch) {
    133 		case 'f':
    134 			freq = atoi(optarg);
    135 			break;
    136 		case 'h':
    137 		case '?':
    138 		default:
    139 			//fprintf(stderr, _("usage: hebraize [-u] [-e command] [-a] [-f] [-l limit] [file]\n"));
    140 			fprintf(stderr, _("usage: hebraize TODO\n"));
    141 			exit(1);
    142 		}
    143 	argc -= optind;
    144 	argv += optind;
    145 
    146 	shell = getenv("SHELL");
    147 	if (shell == NULL)
    148 		shell = "/bin/sh";
    149 
    150         getmaster();
    151         fixtty();
    152 
    153 	sigemptyset(&sa.sa_mask);
    154 	sa.sa_flags = 0;
    155 	sa.sa_handler = finish;
    156 	sigaction(SIGCHLD, &sa, NULL);
    157         child = fork();
    158         if (child < 0) {
    159                 if (!force) perror("fork");
    160                 fail();
    161         }
    162         if (child == 0) {
    163                 subchild = child = fork();
    164                 if (child < 0) {
    165                         if (!force) perror("fork");
    166                         fail();
    167                 }
    168                 if (child) {
    169                         sa.sa_flags = SA_RESTART;
    170                         sigaction(SIGCHLD, &sa, NULL);
    171                         dooutput();
    172                 } else
    173                         doshell(command);
    174         }
    175         sa.sa_handler = resize;
    176         sa.sa_flags = SA_RESTART;
    177         sigaction(SIGWINCH, &sa, NULL);
    178 	doinput();
    179 
    180 	return 0;
    181 }
    182 
    183 void
    184 doinput()
    185 {
    186 	register int cc;
    187 	char ibuf[BUFSIZ];
    188 
    189 #ifdef HAVE_openpty
    190 	(void) close(slave);
    191 #endif
    192 	while ((cc = read(0, ibuf, BUFSIZ)) > 0)
    193 		(void) write(master, ibuf, cc);
    194 	done();
    195 }
    196 
    197 #include <sys/wait.h>
    198 
    199 void
    200 finish()
    201 {
    202 #if defined(SVR4)
    203 	int status;
    204 #else /* !SVR4 */
    205 	union wait status;
    206 #endif /* !SVR4 */
    207 	register int pid;
    208 
    209 	while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
    210 		if (pid == child)
    211 			break;
    212 }
    213 
    214 struct linebuf {
    215     char str[BUFSIZ + 1]; /* + 1 for an additional NULL character.*/
    216     int len;
    217 };
    218 
    219 
    220 inline int soft(unsigned char c) {
    221   return c == 'e' || c == 'i' || c == 'y' || c == 'E' || c == 'I' || c == 'Y';
    222 }
    223 int vowel(unsigned char c) {
    224   return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || c == 'y'
    225     || c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U' || c == 'Y';
    226 }
    227 inline int final_changes(unsigned char c) {
    228   return c == 0xA7 || c == 0x9E || c == 0xA0 || c == 0xA4;
    229 }
    230 
    231 void
    232 dooutput()
    233 {
    234 	int cc;
    235         int i;
    236         int escape = 0;
    237         int ncc;
    238         unsigned char last = 0;
    239         unsigned char lastw = 0;
    240         int may_voice = 0;
    241 	char obuf[BUFSIZ];
    242 	char nobuf[9*BUFSIZ];
    243         int count = 0;
    244 
    245 	setbuf(stdout, NULL);
    246 	(void) close(0);
    247 #ifdef HAVE_openpty
    248 	(void) close(slave);
    249 #endif
    250 	for (;;) {
    251 
    252 		cc = read(master, obuf, BUFSIZ);
    253                 if (cc <= 0)
    254                   break;
    255                 ncc = 0;
    256                 for (i = 0; i < cc; i++) {
    257                   char c = obuf[i];
    258                   if (escape == 0) {
    259                     if (last == 'c' || last == 'C') {
    260                       if (soft(c)) {
    261                         nobuf[ncc++] = 0x08;
    262                         nobuf[ncc++] = 0xD7;
    263                         nobuf[ncc++] = 0xA1;
    264                       }
    265                     }
    266                     if (last == 'c' || last == 'C') {
    267                       if (soft(c)) {
    268                         nobuf[ncc++] = 0x08;
    269                         nobuf[ncc++] = 0xD7;
    270                         nobuf[ncc++] = 0xA1;
    271                       }
    272                     }
    273                     if (last == 'g' || last == 'G') {
    274                       if (soft(c)) {
    275                         nobuf[ncc++] = 0x08;
    276                         nobuf[ncc++] = 0xD7;
    277                         nobuf[ncc++] = 0x96;
    278                       }
    279                     }
    280                     if ((last == 's' || last == 'S') && may_voice) {
    281                       if (vowel(c)) {
    282                         nobuf[ncc++] = 0x08;
    283                         nobuf[ncc++] = 0xD7;
    284                         nobuf[ncc++] = 0x96;
    285                       }
    286                     }
    287                     if (final_changes(lastw)) {
    288                     //printf("%c %d\n", lastw, lastw == 0x9E);
    289 //                        nobuf[ncc++] = 'A';
    290 //                        nobuf[ncc++] = 'A';
    291 //                        nobuf[ncc++] = 'A';
    292                       if (c == ' ') {
    293                         nobuf[ncc++] = 0x08;
    294                         nobuf[ncc++] = 0xD7;
    295                         nobuf[ncc++] = lastw - 1;
    296                       }
    297                     }
    298                     may_voice = 0;
    299                     if (!(count++ % freq)) {
    300                       switch (c) {
    301                         case 'a':
    302                         case 'A':
    303                           nobuf[ncc++] = 0xD7;
    304                           nobuf[ncc++] = 0x90;
    305                           break;
    306                         case 'b':
    307                         case 'B':
    308                           nobuf[ncc++] = 0xD7;
    309                           nobuf[ncc++] = 0x91;
    310                           break;
    311                         case 'g':
    312                         case 'G':
    313                           nobuf[ncc++] = 0xD7;
    314                           nobuf[ncc++] = 0x92;
    315                           break;
    316                         case 'd':
    317                         case 'D':
    318                           nobuf[ncc++] = 0xD7;
    319                           nobuf[ncc++] = 0x93;
    320                           break;
    321                         case 'e':
    322                         case 'E':
    323                         case 'h':
    324                         case 'H':
    325                           nobuf[ncc++] = 0xD7;
    326                           nobuf[ncc++] = 0x94;
    327                           break;
    328                         case 'v':
    329                         case 'V':
    330                         case 'u':
    331                         case 'U':
    332                         case 'w':
    333                         case 'W':
    334                           nobuf[ncc++] = 0xD7;
    335                           nobuf[ncc++] = 0x95;
    336                           break;
    337                         case 'z':
    338                         case 'Z':
    339                         case 'j':
    340                         case 'J':
    341                           // geresh, but it will make it move
    342                           nobuf[ncc++] = 0xD7;
    343                           nobuf[ncc++] = 0x96;
    344                           break;
    345 
    346                         case 't':
    347                         case 'T':
    348                           nobuf[ncc++] = 0xD7;
    349                           nobuf[ncc++] = 0x98;
    350                           break;
    351                         case 'i':
    352                         case 'I':
    353                           nobuf[ncc++] = 0xD7;
    354                           nobuf[ncc++] = 0x99;
    355                           break;
    356 
    357                         case 'l':
    358                         case 'L':
    359                           nobuf[ncc++] = 0xD7;
    360                           nobuf[ncc++] = 0x9C;
    361                           break;
    362                         case 'm':
    363                         case 'M':
    364                           nobuf[ncc++] = 0xD7;
    365                           nobuf[ncc++] = 0x9E;
    366                           nobuf[ncc-1] = 0x9E;
    367                           break;
    368                         case 'n':
    369                         case 'N':
    370                           nobuf[ncc++] = 0xD7;
    371                           nobuf[ncc++] = 0xA0;
    372                           break;
    373                         case 's':
    374                         case 'S':
    375                           nobuf[ncc++] = 0xD7;
    376                           nobuf[ncc++] = 0xA1;
    377                           may_voice = (vowel(last));
    378                           break;
    379                         
    380                         case 'f':
    381                         case 'F':
    382                         case 'p':
    383                         case 'P':
    384                           nobuf[ncc++] = 0xD7;
    385                           nobuf[ncc++] = 0xA4;
    386                           break;
    387 
    388                         case 'c':
    389                         case 'C':
    390                         case 'k':
    391                         case 'K':
    392                         case 'q':
    393                         case 'Q':
    394                           nobuf[ncc++] = 0xD7;
    395                           nobuf[ncc++] = 0xA7;
    396                           break;
    397                         case 'r':
    398                         case 'R':
    399                           nobuf[ncc++] = 0xD7;
    400                           nobuf[ncc++] = 0xA8;
    401                           break;
    402 
    403                         // schwa
    404                         // case 'e':
    405                         // case 'E':
    406                           nobuf[ncc++] = 0xC6;
    407                           nobuf[ncc++] = 0x8F;
    408                           break;
    409 
    410                         case 0x1B:
    411                           escape = 1;
    412                         default:
    413                           nobuf[ncc++] = c;
    414                       }
    415                     } else {
    416                       switch (c) {
    417                         case 0x1B:
    418                           escape = 1;
    419                         default:
    420                           nobuf[ncc++] = c;
    421                       }
    422                     }
    423                     count = count % freq;
    424                     last = c;
    425                     if (ncc) {
    426                       lastw = nobuf[ncc-1];
    427                       //printf("set lastw to %x because read %d, eqauls %d\n", lastw, c, lastw == 0x9E);
    428                     }
    429                    } else {
    430                     nobuf[ncc++] = c;
    431                     if (escape == 1) {
    432                       if (c == '[') {
    433                         escape = 2;
    434                       } else {
    435                         if (c >= 64 && c <= 95) {
    436                           escape = 0;
    437                         }
    438                       }
    439                     } else if (escape == 2) {
    440                       if (c >= 64 && c <= 126)
    441                         escape = 0;
    442                     }
    443                   }
    444                 }
    445 
    446 		(void) write(1, nobuf, ncc);
    447 	}
    448 	done();
    449 }
    450 
    451 void
    452 doshell(const char* command)
    453 {
    454 	/***
    455 	int t;
    456 
    457 	t = open(_PATH_TTY, O_RDWR);
    458 	if (t >= 0) {
    459 		(void) ioctl(t, TIOCNOTTY, (char *)0);
    460 		(void) close(t);
    461 	}
    462 	***/
    463 	getslave();
    464 	(void) close(master);
    465 	(void) dup2(slave, 0);
    466 	(void) dup2(slave, 1);
    467 	(void) dup2(slave, 2);
    468 	(void) close(slave);
    469 
    470         spawnshell();
    471 	perror(shell);
    472 	fail();
    473 }
    474 
    475 void
    476 fixtty()
    477 {
    478 	struct termios rtt;
    479 
    480 	rtt = tt;
    481 #if defined(SVR4)
    482 #if !defined(XCASE)
    483 #define XCASE 0
    484 #endif
    485 	rtt.c_iflag = 0;
    486 	rtt.c_lflag &= ~(ISIG|ICANON|XCASE|ECHO|ECHOE|ECHOK|ECHONL);
    487 	rtt.c_oflag = OPOST;
    488 	rtt.c_cc[VINTR] = CDEL;
    489 	rtt.c_cc[VQUIT] = CDEL;
    490 	rtt.c_cc[VERASE] = CDEL;
    491 	rtt.c_cc[VKILL] = CDEL;
    492 	rtt.c_cc[VEOF] = 1;
    493 	rtt.c_cc[VEOL] = 0;
    494 #else /* !SVR4 */
    495 	cfmakeraw(&rtt);
    496 	rtt.c_lflag &= ~ECHO;
    497 #endif /* !SVR4 */
    498 	(void) tcsetattr(0, TCSAFLUSH, &rtt);
    499 }
    500 
    501 void
    502 fail()
    503 {
    504         if (force) {
    505                 spawnshell();
    506                 perror(shell);
    507         }
    508 	(void) kill(0, SIGTERM);
    509 	done();
    510 }
    511 
    512 void
    513 done()
    514 {
    515 	if (subchild) {
    516 		(void) close(master);
    517 	} else {
    518 		(void) tcsetattr(0, TCSAFLUSH, &tt);
    519 	}
    520 	exit(0);
    521 }
    522 
    523 void
    524 getmaster()
    525 {
    526 #if defined(SVR4)
    527 	(void) tcgetattr(0, &tt);
    528 	(void) ioctl(0, TIOCGWINSZ, (char *)&win);
    529 	if ((master = open("/dev/ptmx", O_RDWR)) < 0) {
    530 		if (!force) perror("open(\"/dev/ptmx\", O_RDWR)");
    531 		fail();
    532 	}
    533 #else /* !SVR4 */
    534 #ifdef HAVE_openpty
    535 	(void) tcgetattr(0, &tt);
    536 	(void) ioctl(0, TIOCGWINSZ, (char *)&win);
    537 	if (openpty(&master, &slave, NULL, &tt, &win) < 0) {
    538 		fprintf(stderr, _("openpty failed\n"));
    539 		fail();
    540 	}
    541 #else
    542 #ifdef HAVE_getpt
    543 	if ((master = getpt()) < 0) {
    544 		if (!force) perror("getpt()");
    545 		fail();
    546 	}
    547 #else
    548 	char *pty, *bank, *cp;
    549 	struct stat stb;
    550 
    551 	pty = &line[strlen("/dev/ptyp")];
    552 	for (bank = "pqrs"; *bank; bank++) {
    553 		line[strlen("/dev/pty")] = *bank;
    554 		*pty = '0';
    555 		if (stat(line, &stb) < 0)
    556 			break;
    557 		for (cp = "0123456789abcdef"; *cp; cp++) {
    558 			*pty = *cp;
    559 			master = open(line, O_RDWR);
    560 			if (master >= 0) {
    561 				char *tp = &line[strlen("/dev/")];
    562 				int ok;
    563 
    564 				/* verify slave side is usable */
    565 				*tp = 't';
    566 				ok = access(line, R_OK|W_OK) == 0;
    567 				*tp = 'p';
    568 				if (ok) {
    569 					(void) tcgetattr(0, &tt);
    570 				    	(void) ioctl(0, TIOCGWINSZ, 
    571 						(char *)&win);
    572 					return;
    573 				}
    574 				(void) close(master);
    575 			}
    576 		}
    577 	}
    578 	fprintf(stderr, _("Out of pty's\n"));
    579 	fail();
    580 #endif /* not HAVE_getpt */
    581 #endif /* not HAVE_openpty */
    582 #endif /* !SVR4 */
    583 }
    584 
    585 void
    586 getslave()
    587 {
    588 #if defined(SVR4)
    589 	(void) setsid();
    590 	grantpt( master);
    591 	unlockpt(master);
    592 	if ((slave = open((const char *)ptsname(master), O_RDWR)) < 0) {
    593 		if (!force) perror("open(fd, O_RDWR)");
    594 		fail();
    595 	}
    596 	(void) tcsetattr(slave, TCSAFLUSH, &tt);
    597 	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
    598 	(void) ioctl(slave, TIOCSCTTY, 0);
    599 #else /* !SVR4 */
    600 #ifndef HAVE_openpty
    601 	line[strlen("/dev/")] = 't';
    602 	slave = open(line, O_RDWR);
    603 	if (slave < 0) {
    604 		if (!force) perror(line);
    605 		fail();
    606 	}
    607 	(void) tcsetattr(slave, TCSAFLUSH, &tt);
    608 	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
    609 #endif
    610 	(void) setsid();
    611 	(void) ioctl(slave, TIOCSCTTY, 0);
    612 #endif /* SVR4 */
    613 }
    614 
    615 void
    616 spawnshell()
    617 {
    618         force = 0;
    619 
    620 	if (!command) {
    621 		execl(shell, strrchr(shell, '/') + 1, "-i", NULL);
    622 	} else {
    623 		execl(shell, strrchr(shell, '/') + 1, "-c", command, NULL);
    624 	}
    625 }