hebraize

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

hebraize.c (16906B)


      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 #include <stropts.h>
     57 #endif /* SVR4 */
     58 
     59 #include <sys/time.h>
     60 
     61 #define HAVE_inet_aton
     62 #define HAVE_scsi_h
     63 #define HAVE_kd_h
     64 
     65 #define _(FOO) FOO
     66 
     67 #ifdef HAVE_openpty
     68 #include <libutil.h>
     69 #endif
     70 
     71 #if defined(SVR4) && !defined(CDEL)
     72 #if defined(_POSIX_VDISABLE)
     73 #define CDEL _POSIX_VDISABLE
     74 #elif defined(CDISABLE)
     75 #define CDEL CDISABLE
     76 #else /* not _POSIX_VISIBLE && not CDISABLE */
     77 #define CDEL 255
     78 #endif /* not _POSIX_VISIBLE && not CDISABLE */
     79 #endif /* SVR4 && ! CDEL */
     80 
     81 void done(void);
     82 void fail(void);
     83 void fixtty(void);
     84 void getmaster(void);
     85 void getslave(void);
     86 void doinput(void);
     87 void dooutput(void);
     88 void doshell(const char*);
     89 void spawnshell();
     90 
     91 char	*shell;
     92 int	master;
     93 int	slave;
     94 int	child;
     95 int	subchild;
     96 int     freq;
     97 
     98 struct	termios tt;
     99 struct	winsize win;
    100 int	lb;
    101 int	l;
    102 #if !defined(SVR4)
    103 #ifndef HAVE_openpty
    104 char	line[] = "/dev/ptyXX";
    105 #endif
    106 #endif /* !SVR4 */
    107 int	aflg;
    108 int	force;
    109 int	limit;
    110 char *command = NULL;
    111 
    112 static void
    113 resize(int dummy) {
    114 	/* transmit window change information to the child */
    115 	(void) ioctl(0, TIOCGWINSZ, (char *)&win);
    116 	(void) ioctl(master, TIOCSWINSZ, (char *)&win);
    117 }
    118 
    119 int
    120 main(argc, argv)
    121 	int argc;
    122 	char *argv[];
    123 {
    124 	struct sigaction sa;
    125 	extern int optind;
    126 	int ch;
    127 	void finish();
    128 	char *getenv();
    129 
    130         freq = 1;
    131 
    132 	while ((ch = getopt(argc, argv, "f:h?")) != EOF)
    133 		switch((char)ch) {
    134 		case 'f':
    135 			freq = atoi(optarg);
    136 			break;
    137 		case 'h':
    138 		case '?':
    139 		default:
    140 			//fprintf(stderr, _("usage: hebraize [-u] [-e command] [-a] [-f] [-l limit] [file]\n"));
    141 			fprintf(stderr, _("usage: hebraize TODO\n"));
    142 			exit(1);
    143 		}
    144 	argc -= optind;
    145 	argv += optind;
    146 
    147 	shell = getenv("SHELL");
    148 	if (shell == NULL)
    149 		shell = "/bin/sh";
    150 
    151         getmaster();
    152         fixtty();
    153 
    154 	sigemptyset(&sa.sa_mask);
    155 	sa.sa_flags = 0;
    156 	sa.sa_handler = finish;
    157 	sigaction(SIGCHLD, &sa, NULL);
    158         child = fork();
    159         if (child < 0) {
    160                 if (!force) perror("fork");
    161                 fail();
    162         }
    163         if (child == 0) {
    164                 subchild = child = fork();
    165                 if (child < 0) {
    166                         if (!force) perror("fork");
    167                         fail();
    168                 }
    169                 if (child) {
    170                         sa.sa_flags = SA_RESTART;
    171                         sigaction(SIGCHLD, &sa, NULL);
    172                         dooutput();
    173                 } else
    174                         doshell(command);
    175         }
    176         sa.sa_handler = resize;
    177         sa.sa_flags = SA_RESTART;
    178         sigaction(SIGWINCH, &sa, NULL);
    179 	doinput();
    180 
    181 	return 0;
    182 }
    183 
    184 void
    185 doinput()
    186 {
    187 	register int cc;
    188 	char ibuf[BUFSIZ];
    189 
    190 #ifdef HAVE_openpty
    191 	(void) close(slave);
    192 #endif
    193 	while ((cc = read(0, ibuf, BUFSIZ)) > 0)
    194 		(void) write(master, ibuf, cc);
    195 	done();
    196 }
    197 
    198 #include <sys/wait.h>
    199 
    200 void
    201 finish()
    202 {
    203 #if defined(SVR4)
    204 	int status;
    205 #else /* !SVR4 */
    206 	union wait status;
    207 #endif /* !SVR4 */
    208 	register int pid;
    209 
    210 	while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
    211 		if (pid == child)
    212 			break;
    213 }
    214 
    215 struct linebuf {
    216     char str[BUFSIZ + 1]; /* + 1 for an additional NULL character.*/
    217     int len;
    218 };
    219 
    220 
    221 inline int soft(unsigned char c) {
    222   return c == 'e' || c == 'i' || c == 'y' || c == 'E' || c == 'I' || c == 'Y';
    223 }
    224 int vowel(unsigned char c) {
    225   return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || c == 'y'
    226     || c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U' || c == 'Y';
    227 }
    228 inline int final_changes(unsigned char c) {
    229   return c == 0xA7 || c == 0x9E || c == 0xA0 || c == 0xA4;
    230 }
    231 
    232 void
    233 dooutput()
    234 {
    235 	int cc;
    236         int i;
    237         int escape = 0;
    238         int ncc;
    239         unsigned char last = 0;
    240         unsigned char lastw = 0;
    241         int may_voice = 0;
    242 	char obuf[BUFSIZ];
    243 	char nobuf[9*BUFSIZ];
    244         int count = 0;
    245 
    246 	setbuf(stdout, NULL);
    247 	(void) close(0);
    248 #ifdef HAVE_openpty
    249 	(void) close(slave);
    250 #endif
    251 	for (;;) {
    252 
    253 		cc = read(master, obuf, BUFSIZ);
    254                 if (cc <= 0)
    255                   break;
    256                 ncc = 0;
    257                 for (i = 0; i < cc; i++) {
    258                   char c = obuf[i];
    259                   if (escape == 0) {
    260                     if (last == 'c' || last == 'C') {
    261                       if (soft(c)) {
    262                         nobuf[ncc++] = 0x08;
    263                         nobuf[ncc++] = 0xD7;
    264                         nobuf[ncc++] = 0xA1;
    265                       }
    266                     }
    267                     if (last == 'c' || last == 'C') {
    268                       if (soft(c)) {
    269                         nobuf[ncc++] = 0x08;
    270                         nobuf[ncc++] = 0xD7;
    271                         nobuf[ncc++] = 0xA1;
    272                       }
    273                     }
    274                     if (last == 'g' || last == 'G') {
    275                       if (soft(c)) {
    276                         nobuf[ncc++] = 0x08;
    277                         nobuf[ncc++] = 0xD7;
    278                         nobuf[ncc++] = 0x96;
    279                       }
    280                     }
    281                     if ((last == 's' || last == 'S') && may_voice) {
    282                       if (vowel(c)) {
    283                         nobuf[ncc++] = 0x08;
    284                         nobuf[ncc++] = 0xD7;
    285                         nobuf[ncc++] = 0x96;
    286                       }
    287                     }
    288                     if (final_changes(lastw)) {
    289                     //printf("%c %d\n", lastw, lastw == 0x9E);
    290 //                        nobuf[ncc++] = 'A';
    291 //                        nobuf[ncc++] = 'A';
    292 //                        nobuf[ncc++] = 'A';
    293                       if (c == ' ') {
    294                         nobuf[ncc++] = 0x08;
    295                         nobuf[ncc++] = 0xD7;
    296                         nobuf[ncc++] = lastw - 1;
    297                       }
    298                     }
    299                     may_voice = 0;
    300                     if (!(count++ % freq)) {
    301                       switch (c) {
    302                         case 'a':
    303                         case 'A':
    304                           nobuf[ncc++] = 0xD7;
    305                           nobuf[ncc++] = 0x90;
    306                           break;
    307                         case 'b':
    308                         case 'B':
    309                           nobuf[ncc++] = 0xD7;
    310                           nobuf[ncc++] = 0x91;
    311                           break;
    312                         case 'g':
    313                         case 'G':
    314                           nobuf[ncc++] = 0xD7;
    315                           nobuf[ncc++] = 0x92;
    316                           break;
    317                         case 'd':
    318                         case 'D':
    319                           nobuf[ncc++] = 0xD7;
    320                           nobuf[ncc++] = 0x93;
    321                           break;
    322                         case 'e':
    323                         case 'E':
    324                         case 'h':
    325                         case 'H':
    326                           nobuf[ncc++] = 0xD7;
    327                           nobuf[ncc++] = 0x94;
    328                           break;
    329                         case 'v':
    330                         case 'V':
    331                         case 'u':
    332                         case 'U':
    333                         case 'w':
    334                         case 'W':
    335                           nobuf[ncc++] = 0xD7;
    336                           nobuf[ncc++] = 0x95;
    337                           break;
    338                         case 'z':
    339                         case 'Z':
    340                         case 'j':
    341                         case 'J':
    342                           // geresh, but it will make it move
    343                           nobuf[ncc++] = 0xD7;
    344                           nobuf[ncc++] = 0x96;
    345                           break;
    346 
    347                         case 't':
    348                         case 'T':
    349                           nobuf[ncc++] = 0xD7;
    350                           nobuf[ncc++] = 0x98;
    351                           break;
    352                         case 'i':
    353                         case 'I':
    354                           nobuf[ncc++] = 0xD7;
    355                           nobuf[ncc++] = 0x99;
    356                           break;
    357 
    358                         case 'l':
    359                         case 'L':
    360                           nobuf[ncc++] = 0xD7;
    361                           nobuf[ncc++] = 0x9C;
    362                           break;
    363                         case 'm':
    364                         case 'M':
    365                           nobuf[ncc++] = 0xD7;
    366                           nobuf[ncc++] = 0x9E;
    367                           nobuf[ncc-1] = 0x9E;
    368                           break;
    369                         case 'n':
    370                         case 'N':
    371                           nobuf[ncc++] = 0xD7;
    372                           nobuf[ncc++] = 0xA0;
    373                           break;
    374                         case 's':
    375                         case 'S':
    376                           nobuf[ncc++] = 0xD7;
    377                           nobuf[ncc++] = 0xA1;
    378                           may_voice = (vowel(last));
    379                           break;
    380                         
    381                         case 'f':
    382                         case 'F':
    383                         case 'p':
    384                         case 'P':
    385                           nobuf[ncc++] = 0xD7;
    386                           nobuf[ncc++] = 0xA4;
    387                           break;
    388 
    389                         case 'c':
    390                         case 'C':
    391                         case 'k':
    392                         case 'K':
    393                         case 'q':
    394                         case 'Q':
    395                           nobuf[ncc++] = 0xD7;
    396                           nobuf[ncc++] = 0xA7;
    397                           break;
    398                         case 'r':
    399                         case 'R':
    400                           nobuf[ncc++] = 0xD7;
    401                           nobuf[ncc++] = 0xA8;
    402                           break;
    403 
    404                         // schwa
    405                         // case 'e':
    406                         // case 'E':
    407                           nobuf[ncc++] = 0xC6;
    408                           nobuf[ncc++] = 0x8F;
    409                           break;
    410 
    411                         case 0x1B:
    412                           escape = 1;
    413                         default:
    414                           nobuf[ncc++] = c;
    415                       }
    416                     } else {
    417                       switch (c) {
    418                         case 0x1B:
    419                           escape = 1;
    420                         default:
    421                           nobuf[ncc++] = c;
    422                       }
    423                     }
    424                     count = count % freq;
    425                     last = c;
    426                     if (ncc) {
    427                       lastw = nobuf[ncc-1];
    428                       //printf("set lastw to %x because read %d, eqauls %d\n", lastw, c, lastw == 0x9E);
    429                     }
    430                    } else {
    431                     nobuf[ncc++] = c;
    432                     if (escape == 1) {
    433                       if (c == '[') {
    434                         escape = 2;
    435                       } else {
    436                         if (c >= 64 && c <= 95) {
    437                           escape = 0;
    438                         }
    439                       }
    440                     } else if (escape == 2) {
    441                       if (c >= 64 && c <= 126)
    442                         escape = 0;
    443                     }
    444                   }
    445                 }
    446 
    447 		(void) write(1, nobuf, ncc);
    448 	}
    449 	done();
    450 }
    451 
    452 void
    453 doshell(const char* command)
    454 {
    455 	/***
    456 	int t;
    457 
    458 	t = open(_PATH_TTY, O_RDWR);
    459 	if (t >= 0) {
    460 		(void) ioctl(t, TIOCNOTTY, (char *)0);
    461 		(void) close(t);
    462 	}
    463 	***/
    464 	getslave();
    465 	(void) close(master);
    466 	(void) dup2(slave, 0);
    467 	(void) dup2(slave, 1);
    468 	(void) dup2(slave, 2);
    469 	(void) close(slave);
    470 
    471         spawnshell();
    472 	perror(shell);
    473 	fail();
    474 }
    475 
    476 void
    477 fixtty()
    478 {
    479 	struct termios rtt;
    480 
    481 	rtt = tt;
    482 #if defined(SVR4)
    483 #if !defined(XCASE)
    484 #define XCASE 0
    485 #endif
    486 	rtt.c_iflag = 0;
    487 	rtt.c_lflag &= ~(ISIG|ICANON|XCASE|ECHO|ECHOE|ECHOK|ECHONL);
    488 	rtt.c_oflag = OPOST;
    489 	rtt.c_cc[VINTR] = CDEL;
    490 	rtt.c_cc[VQUIT] = CDEL;
    491 	rtt.c_cc[VERASE] = CDEL;
    492 	rtt.c_cc[VKILL] = CDEL;
    493 	rtt.c_cc[VEOF] = 1;
    494 	rtt.c_cc[VEOL] = 0;
    495 #else /* !SVR4 */
    496 	cfmakeraw(&rtt);
    497 	rtt.c_lflag &= ~ECHO;
    498 #endif /* !SVR4 */
    499 	(void) tcsetattr(0, TCSAFLUSH, &rtt);
    500 }
    501 
    502 void
    503 fail()
    504 {
    505         if (force) {
    506                 spawnshell();
    507                 perror(shell);
    508         }
    509 	(void) kill(0, SIGTERM);
    510 	done();
    511 }
    512 
    513 void
    514 done()
    515 {
    516 	if (subchild) {
    517 		(void) close(master);
    518 	} else {
    519 		(void) tcsetattr(0, TCSAFLUSH, &tt);
    520 	}
    521 	exit(0);
    522 }
    523 
    524 void
    525 getmaster()
    526 {
    527 #if defined(SVR4)
    528 	(void) tcgetattr(0, &tt);
    529 	(void) ioctl(0, TIOCGWINSZ, (char *)&win);
    530 	if ((master = open("/dev/ptmx", O_RDWR)) < 0) {
    531 		if (!force) perror("open(\"/dev/ptmx\", O_RDWR)");
    532 		fail();
    533 	}
    534 #else /* !SVR4 */
    535 #ifdef HAVE_openpty
    536 	(void) tcgetattr(0, &tt);
    537 	(void) ioctl(0, TIOCGWINSZ, (char *)&win);
    538 	if (openpty(&master, &slave, NULL, &tt, &win) < 0) {
    539 		fprintf(stderr, _("openpty failed\n"));
    540 		fail();
    541 	}
    542 #else
    543 #ifdef HAVE_getpt
    544 	if ((master = getpt()) < 0) {
    545 		if (!force) perror("getpt()");
    546 		fail();
    547 	}
    548 #else
    549 	char *pty, *bank, *cp;
    550 	struct stat stb;
    551 
    552 	pty = &line[strlen("/dev/ptyp")];
    553 	for (bank = "pqrs"; *bank; bank++) {
    554 		line[strlen("/dev/pty")] = *bank;
    555 		*pty = '0';
    556 		if (stat(line, &stb) < 0)
    557 			break;
    558 		for (cp = "0123456789abcdef"; *cp; cp++) {
    559 			*pty = *cp;
    560 			master = open(line, O_RDWR);
    561 			if (master >= 0) {
    562 				char *tp = &line[strlen("/dev/")];
    563 				int ok;
    564 
    565 				/* verify slave side is usable */
    566 				*tp = 't';
    567 				ok = access(line, R_OK|W_OK) == 0;
    568 				*tp = 'p';
    569 				if (ok) {
    570 					(void) tcgetattr(0, &tt);
    571 				    	(void) ioctl(0, TIOCGWINSZ, 
    572 						(char *)&win);
    573 					return;
    574 				}
    575 				(void) close(master);
    576 			}
    577 		}
    578 	}
    579 	fprintf(stderr, _("Out of pty's\n"));
    580 	fail();
    581 #endif /* not HAVE_getpt */
    582 #endif /* not HAVE_openpty */
    583 #endif /* !SVR4 */
    584 }
    585 
    586 void
    587 getslave()
    588 {
    589 #if defined(SVR4)
    590 	(void) setsid();
    591 	grantpt( master);
    592 	unlockpt(master);
    593 	if ((slave = open((const char *)ptsname(master), O_RDWR)) < 0) {
    594 		if (!force) perror("open(fd, O_RDWR)");
    595 		fail();
    596 	}
    597 	if (isastream(slave)) {
    598 		if (ioctl(slave, I_PUSH, "ptem") < 0) {
    599 			if (!force) perror("ioctl(fd, I_PUSH, ptem)");
    600 			fail();
    601 		}
    602 		if (ioctl(slave, I_PUSH, "ldterm") < 0) {
    603 			if (!force) perror("ioctl(fd, I_PUSH, ldterm)");
    604 			fail();
    605 		}
    606 #ifndef _HPUX_SOURCE
    607 		if (ioctl(slave, I_PUSH, "ttcompat") < 0) {
    608 			if (!force) perror("ioctl(fd, I_PUSH, ttcompat)");
    609 			fail();
    610 		}
    611 #endif
    612 	}
    613 	(void) tcsetattr(slave, TCSAFLUSH, &tt);
    614 	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
    615 	(void) ioctl(slave, TIOCSCTTY, 0);
    616 #else /* !SVR4 */
    617 #ifndef HAVE_openpty
    618 	line[strlen("/dev/")] = 't';
    619 	slave = open(line, O_RDWR);
    620 	if (slave < 0) {
    621 		if (!force) perror(line);
    622 		fail();
    623 	}
    624 	(void) tcsetattr(slave, TCSAFLUSH, &tt);
    625 	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
    626 #endif
    627 	(void) setsid();
    628 	(void) ioctl(slave, TIOCSCTTY, 0);
    629 #endif /* SVR4 */
    630 }
    631 
    632 void
    633 spawnshell()
    634 {
    635         force = 0;
    636 
    637 	if (!command) {
    638 		execl(shell, strrchr(shell, '/') + 1, "-i", NULL);
    639 	} else {
    640 		execl(shell, strrchr(shell, '/') + 1, "-c", command, NULL);
    641 	}
    642 }