diff --git a/src/syncterm/ripper.c b/src/syncterm/ripper.c
index 0484f7e0ebe4aace3ffb253123ee4fe01204fa6e..7c2bcfa4ba2e19e7f3a6aa2e7f535845ef3031df 100644
--- a/src/syncterm/ripper.c
+++ b/src/syncterm/ripper.c
@@ -268,6 +268,9 @@ static struct {
 	int clipx;
 	int clipy;
 	struct mouse_field *saved_mfields;
+	struct {
+		int sx, sy, ex, ey, xpos, ypos;
+	} text_region;
 } rip = {
 	RIP_STATE_BOL,
 	RIP_STATE_FLUSHING,
@@ -301,6 +304,8 @@ static struct {
 	false,
 	ANSI_STATE_NONE,
 	0, 0,
+	NULL,
+	{0, 0, 0, 0, 0, 0},
 };
 
 static const uint16_t rip_line_patterns[4] = {
@@ -7752,6 +7757,13 @@ map_rip_x(int x)
 {
 	int i;
 
+	if (x < 0 || x >= rip.x_dim) {
+		double dx = x;
+		dx *= rip.x_max;
+		dx /= rip.x_dim;
+		return roundl(dx);
+	}
+
 	if (rip.xmap == NULL) {
 		rip.xmap = malloc(rip.x_dim * sizeof(int));
 		if (rip.xmap == NULL) {
@@ -7773,6 +7785,13 @@ map_rip_y(int y)
 {
 	int i;
 
+	if (y < 0 || y >= rip.y_dim) {
+		double dy = y;
+		dy *= rip.y_max;
+		dy /= rip.y_dim;
+		return roundl(dy);
+	}
+
 	if (rip.ymap == NULL) {
 		rip.ymap = malloc(rip.y_dim * sizeof(int));
 		if (rip.ymap == NULL) {
@@ -8056,7 +8075,7 @@ buffer_data(const BYTE *buf, unsigned len)
 static int
 next_char(const char *buf, size_t *pos)
 {
-	if (buf[*pos] == '\\') {
+	while (buf[*pos] == '\\') {
 		(*pos)++;
 		if (buf[*pos] == '\r') {
 			(*pos)++;
@@ -8065,7 +8084,11 @@ next_char(const char *buf, size_t *pos)
 		}
 		else if (buf[*pos] == '\n')
 			(*pos)++;
+		else
+			return (uint8_t)buf[*pos];
 	}
+	if (buf[*pos] == '!')
+		return -1;
 	else if (buf[*pos] == '|')
 		return -1;
 	else if (buf[*pos] == '\r')
@@ -8249,6 +8272,17 @@ char_top_bottom(char ch, int *top, int *bottom)
 	}
 }
 
+static int
+font_height()
+{
+	int mult = stroke_mults[rip.font.size];
+	int div = stroke_divs[rip.font.size];
+
+	if (rip.font.num == 0)
+		return 8 * rip.font.size;
+	return (((char)rip_fonts[rip.font.num - 1][0x88]) - ((char)rip_fonts[rip.font.num - 1][0x8a])) * mult / div;
+}
+
 static void
 write_char(char ch)
 {
@@ -8289,7 +8323,7 @@ write_char(char ch)
 						if (this_font[fontoffset] & (0x80 >> x)) {
 							// NOTE: Bitmap fonts don't use write mode...
 							//draw_pixel(rip.x + (x * rip.font.size) + xs, rip.y + (y * rip.font.size)+ ys);
-							set_pixel(rip.x + (x * rip.font.size) + xs, rip.y + (y * rip.font.size)+ ys, ega_colours[rip.color]);
+							set_pixel(rip.x + (x * rip.font.size) + xs, rip.y + (y * rip.font.size)+ ys, map_rip_color(rip.color));
 						}
 					}
 				}
@@ -8766,14 +8800,14 @@ draw_button(struct rip_button_style *but, bool inverted)
 		cc = ega_colours[0x0f ^ but->ccorner];
 	}
 	else {
-		fg = ega_colours[but->cfore];
+		fg = map_rip_color(but->cfore);
 		bg = ega_colours[0];
-		ds = ega_colours[but->cdshadow];
-		ch = ega_colours[but->chighlight];
-		cs = ega_colours[but->cshadow];
-		su = ega_colours[but->csurface];
-		ul = ega_colours[but->culine];
-		cc = ega_colours[but->ccorner];
+		ds = map_rip_color(but->cdshadow);
+		ch = map_rip_color(but->chighlight);
+		cs = map_rip_color(but->cshadow);
+		su = map_rip_color(but->csurface);
+		ul = map_rip_color(but->culine);
+		cc = map_rip_color(but->ccorner);
 	}
 
 	ox = but->box.x1;
@@ -9592,7 +9626,7 @@ draw_ellipse(int x1, int y1, int arg1, int arg2, int x2, int y2)
 		    y1 - nearbyint(sin((M_PI / 180.0) * arg3) * y2),
 		    x1 + nearbyint(cos((1.0 + arg3) * (M_PI / 180.0)) * x2),
 		    y1 - nearbyint(sin((1.0 + arg3) * (M_PI / 180.0)) * y2),
-		    ega_colours[rip.color], 0xffff, rip.line_width);
+		    map_rip_color(rip.color), 0xffff, rip.line_width);
 	}
 }
 
@@ -10023,10 +10057,16 @@ do_rip_command(int level, int sublevel, int cmd, const char *rawargs)
 							GET_XY2();
 							arg1 = parse_mega(&args[8], 2);
 							pthread_mutex_lock(&vstatlock);
-							arg3 = ceil((arg1 * vstat.scrnheight) / (((double)(vstat.scrnwidth)) * 3 / 4));
+							if (vstat.scale_numerator == 729 && vstat.scale_denominator == 1000) {
+								// Detect EGA mode and use the same value as RIPterm did.
+								arg3 = (arg1 * 7750 / 10000);
+							}
+							else {
+								arg3 = arg1 * vstat.scale_numerator / vstat.scale_denominator;
+							}
 							pthread_mutex_unlock(&vstatlock);
 							if (abs(arg3 - arg1) == 360)
-								full_ellipse(x1, y2, x2, y2, false);
+								full_ellipse(x1, y1, x2, y2, false);
 							else
 								draw_ellipse(x1, y1, x2, y2, arg1, arg3);
 							break;
@@ -10134,9 +10174,9 @@ do_rip_command(int level, int sublevel, int cmd, const char *rawargs)
 							struct ciolib_pixels *pix = getpixels(rip.viewport.sx, rip.viewport.sy, rip.viewport.ex, arg2, false);
 							FREE_AND_NULL(pix->pixelsb);
 							// Blammo goes the stack!
-							fg = ega_colours[arg1];
+							fg = map_rip_color(arg1);
 							uint32_t ffg, fbg;
-							ffg = ega_colours[rip.fill_color];
+							ffg = map_rip_color(rip.fill_color);
 							fbg = ega_colours[0];
 							if (x1 < pix->width && y1 < pix->height)
 								broken_flood_fill(pix, x1, y1, fg, ffg, fbg, rip.fill_color == 0, y1);
@@ -10165,6 +10205,27 @@ do_rip_command(int level, int sublevel, int cmd, const char *rawargs)
 							 * current drawing color and line thickness.  The Line Pattern feature
 							 * does not apply to this command.
 							 */
+							handled = true;
+							if (no_viewport())
+								break;
+							GET_XY2();
+							arg1 = parse_mega(&args[8], 2);
+							pthread_mutex_lock(&vstatlock);
+							if (vstat.scale_numerator == 729 && vstat.scale_denominator == 1000) {
+								// Detect EGA mode and use the same value as RIPterm did.
+								arg3 = (arg1 * 7750 / 10000);
+							}
+							else {
+								arg3 = arg1 * vstat.scale_numerator / vstat.scale_denominator;
+							}
+							pthread_mutex_unlock(&vstatlock);
+							if (abs(arg3 - arg1) == 360)
+								full_ellipse(x1, y1, x2, y2, false);
+							else
+								draw_ellipse(x1, y1, x2, y2, arg1, arg3);
+							draw_line(x1, y1, x1 + nearbyint(cos(M_PI / 180.0) * arg1) * x2, y1 + nearbyint(sin(M_PI / 180.0) * arg1) * y2);
+							draw_line(x1, y1, x1 + nearbyint(cos(M_PI / 180.0) * arg3) * x2, y1 + nearbyint(sin(M_PI / 180.0) * arg3) * y2);
+							puts("TODO: Needs to fill...");
 							break;
 						case 'L':	// RIP_LINE !|L <x0> <y0> <x1> <y1>
 							/* This command will draw a line in the current drawing color, using the
@@ -10249,7 +10310,7 @@ do_rip_command(int level, int sublevel, int cmd, const char *rawargs)
 							handled = true;
 							if (no_viewport())
 								break;
-							fg = ega_colours[rip.color];
+							fg = map_rip_color(rip.color);
 							arg1 = parse_mega(&args[0], 2);
 							for (i = 0; i < arg1; i++) {
 								if (i == 0) {
@@ -10407,7 +10468,7 @@ do_rip_command(int level, int sublevel, int cmd, const char *rawargs)
 							if (no_viewport())
 								break;
 							GET_XY();
-							set_pixel(x1, y1, ega_colours[rip.color]);
+							set_pixel(x1, y1, map_rip_color(rip.color));
 							break;
 						case 'Y':	// RIP_FONT_STYLE !|Y <font> <direction> <size> <res>
 							/*
@@ -10561,7 +10622,9 @@ do_rip_command(int level, int sublevel, int cmd, const char *rawargs)
 							curr_ega_palette[arg1] = arg2;
 							attr2palette(arg1, &fg, NULL);
 							setpalette(fg, ega_palette[arg2][0], ega_palette[arg2][1], ega_palette[arg2][2]);
-							ega_colours[arg1] = fg;
+							// TODO: Extended palette.
+							if (arg1 < 16)
+								ega_colours[arg1] = fg;
 							break;
 						case 'c':	// RIP_COLOR !|c <color>
 							/* This command sets the color for drawing lines, circles, arcs,
@@ -10647,7 +10710,7 @@ do_rip_command(int level, int sublevel, int cmd, const char *rawargs)
 								arg2 += 360;
 							// TODO: Use 'o' command ellipse when possible...
 							puts("TODO: Needs to fill...");
-							fg = ega_colours[rip.color];
+							fg = map_rip_color(rip.color);
 							set_line(x1, y1, x1 + (x2 * cos(arg1 * (M_PI / 180.0))),
 							    y1 - (y2 * sin(arg1 * (M_PI / 180.0))), fg, 0xffff, rip.line_width);
 							for (arg3 = arg1; arg3 < arg2; arg3++) {
@@ -12082,7 +12145,7 @@ do_rip_command(int level, int sublevel, int cmd, const char *rawargs)
 										co |= (((planes[(row * 2) + (j / 8)] >> (7 - (j & 7))) & 1) << 1);
 										co |= (((planes[(row * 1) + (j / 8)] >> (7 - (j & 7))) & 1) << 2);
 										co |= (((planes[(row * 0) + (j / 8)] >> (7 - (j & 7))) & 1) << 3);
-										*(op++) = ega_colours[co];
+										*(op++) = map_rip_color(co);
 									}
 								}
 								if (pix) {
@@ -12339,7 +12402,14 @@ do_rip_command(int level, int sublevel, int cmd, const char *rawargs)
 							 * NOTE:  The "res" parameter is two bytes wide and is RESERVED for
 							 *        future use.
 							 */
-							// TODO: Justify things.
+							handled = true;
+							GET_XY2();
+							rip.text_region.sx = x1;
+							rip.text_region.sy = y1;
+							rip.text_region.ex = x2;
+							rip.text_region.ey = y2;
+							rip.text_region.xpos = 0;
+							rip.text_region.ypos = 0;
 							break;
 						case 't':	// RIP_REGION_TEXT !|1t <justify> <text-string>
 							/* A number of these commands may come sandwiched between the
@@ -12375,6 +12445,36 @@ do_rip_command(int level, int sublevel, int cmd, const char *rawargs)
 							 * formatted text block.
 							 */
 							// TODO: The things that are justified...
+							handled = true;
+							arg1 = parse_mega(&args[0], 1);
+							if (arg1) {
+								printf("TODO: Justify %d\n", arg1);
+							}
+							{
+								int oldsx = rip.viewport.sx;
+								int oldsy = rip.viewport.sy;
+								int oldex = rip.viewport.ex;
+								int oldey = rip.viewport.ey;
+								int oldx = rip.x;
+								int oldy = rip.y;
+
+								rip.viewport.sx = rip.text_region.sx;
+								rip.viewport.sy = rip.text_region.sy;
+								rip.viewport.ex = rip.text_region.ex;
+								rip.viewport.ey = rip.text_region.ey;
+								rip.x = rip.text_region.xpos;
+								rip.y = rip.text_region.ypos;
+
+								write_text(&args[1]);
+								rip.text_region.ypos += font_height();
+
+								rip.viewport.sx = oldsx;
+								rip.viewport.sy = oldsy;
+								rip.viewport.ex = oldex;
+								rip.viewport.ey = oldey;
+								rip.x = oldx;
+								rip.y = oldy;
+							}
 							break;
 						case 'U':	// RIP_BUTTON !|1U <x0> <y0> <x1> <y1> <hotkey> <flags> <res> <text>
 							/* This command physically creates a new Button using the previously
@@ -12658,16 +12758,17 @@ do_rip_command(int level, int sublevel, int cmd, const char *rawargs)
 			}
 			break;
 	}
-	free(args);
 	if (!handled) {
 		printf("Unhandled command: Level: %d, SubLevel: %d, cmd: %d, args: %s\n", level, sublevel, cmd, args);
 		fflush(stdout);
 	}
+	free(args);
 }
 
 static void
 do_rip_string(const char *buf, size_t len)
 {
+	enum do_states rs = NEED_BANG;	// Reset state...
 	enum do_states ds = NEED_BANG;
 	int ch;
 	size_t pos;
@@ -12680,54 +12781,56 @@ do_rip_string(const char *buf, size_t len)
 		switch (ds) {
 			case NEED_BANG:
 				ch = next_char(buf, &pos);
-				if (ch == '!' || ch == '\x01' || ch == '\x02')
+				if ((ch == -1 && buf[pos] == '!') || ch == '\x01' || ch == '\x02')
 					ds = NEED_PIPE;
 				break;
 			case NEED_PIPE:
-				if (next_char(buf, &pos) == -1) {
+				if (next_char(buf, &pos) == -1 && buf[pos] == '|') {
 					level = 0;
 					sublevel = 0;
 					cmd = -1;
 					ds = NEED_LEVEL;
+					break;
 				}
+				ds = rs;
 				break;
 			case NEED_LEVEL:
 				ch = next_char(buf, &pos);
-				if (ch == -1)
-					break;
 				if (ch >= '1' && ch <= '9') {
 					level = ch - '0';
 					ds = NEED_SUBLEVEL;
+					break;
 				}
-				else {
-					level = 0;
-					sublevel = 0;
-					cmd = ch;
-					arg_start = 0;
-					ds = ARGUMENTS;
+				else if (ch == -1) {
+					ds = rs;
+					break;
 				}
+				level = 0;
+				sublevel = 0;
+				cmd = ch;
+				arg_start = 0;
+				ds = ARGUMENTS;
 				break;
 			case NEED_SUBLEVEL:
 				ch = next_char(buf, &pos);
-				if (ch == -1) {
-					ds = NEED_LEVEL;
-					break;
-				}
 				if (ch >= '1' && ch <= '9') {
 					sublevel = ch - '0';
 					ds = NEED_COMMAND;
+					break;
 				}
-				else {
-					sublevel = 0;
-					cmd = ch;
-					arg_start = 0;
-					ds = ARGUMENTS;
+				else if (ch == -1) {
+					ds = rs;
+					break;
 				}
+				sublevel = 0;
+				cmd = ch;
+				arg_start = 0;
+				ds = ARGUMENTS;
 				break;
 			case NEED_COMMAND:
 				ch = next_char(buf, &pos);
 				if (ch == -1) {
-					ds = NEED_LEVEL;
+					ds = rs;
 					break;
 				}
 				cmd = ch;
@@ -12738,9 +12841,13 @@ do_rip_string(const char *buf, size_t len)
 				ch = next_char(buf, &pos);
 				if (arg_start == 0)
 					arg_start = pos;
-				if (ch == -1 || ch == '\r') {
+				if (ch == -1 || ch == '!' || ch == '|') {
 					do_rip_command(level, sublevel, cmd, &buf[arg_start]);
-					ds = NEED_LEVEL;
+					if (buf[pos] == '|')
+						ds = NEED_LEVEL;
+					else
+						ds = NEED_PIPE;
+					rs = NEED_PIPE;
 				}
 				break;
 		}
@@ -13693,8 +13800,6 @@ init_rip(int version)
 	rip.y = 0;
 	rip.viewport.sx = 0;
 	rip.viewport.sy = 0;
-	rip.viewport.ex = rip.x_dim - 1;
-	rip.viewport.ey = rip.y_dim - 1;
 	rip.color = 7;
 	rip.font.num = 0;
 	rip.font.vertical = 0;
@@ -13714,6 +13819,8 @@ init_rip(int version)
 	if (rip.y_max > rip.y_dim)
 		rip.y_max = rip.y_dim;
 	pthread_mutex_unlock(&vstatlock);
+	rip.viewport.ex = rip.x_dim - 1;
+	rip.viewport.ey = rip.y_dim - 1;
 
 	pending_len = 0;
 	if (pending)