buffer.c (6464B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20 21#include "terminal/buffer.h" 22#include "terminal/common.h" 23 24#include <guacamole/mem.h> 25 26#include <stdlib.h> 27#include <string.h> 28 29guac_terminal_buffer* guac_terminal_buffer_alloc(int rows, guac_terminal_char* default_character) { 30 31 /* Allocate scrollback */ 32 guac_terminal_buffer* buffer = 33 guac_mem_alloc(sizeof(guac_terminal_buffer)); 34 35 int i; 36 guac_terminal_buffer_row* row; 37 38 /* Init scrollback data */ 39 buffer->default_character = *default_character; 40 buffer->available = rows; 41 buffer->top = 0; 42 buffer->length = 0; 43 buffer->rows = guac_mem_alloc(sizeof(guac_terminal_buffer_row), buffer->available); 44 45 /* Init scrollback rows */ 46 row = buffer->rows; 47 for (i=0; i<rows; i++) { 48 49 /* Allocate row */ 50 row->available = 256; 51 row->length = 0; 52 row->characters = guac_mem_alloc(sizeof(guac_terminal_char), row->available); 53 54 /* Next row */ 55 row++; 56 57 } 58 59 return buffer; 60 61} 62 63void guac_terminal_buffer_free(guac_terminal_buffer* buffer) { 64 65 int i; 66 guac_terminal_buffer_row* row = buffer->rows; 67 68 /* Free all rows */ 69 for (i=0; i<buffer->available; i++) { 70 guac_mem_free(row->characters); 71 row++; 72 } 73 74 /* Free actual buffer */ 75 guac_mem_free(buffer->rows); 76 guac_mem_free(buffer); 77 78} 79 80guac_terminal_buffer_row* guac_terminal_buffer_get_row(guac_terminal_buffer* buffer, int row, int width) { 81 82 int i; 83 guac_terminal_char* first; 84 guac_terminal_buffer_row* buffer_row; 85 86 /* Normalize row index into a scrollback buffer index */ 87 int index = (buffer->top + row) % buffer->available; 88 if (index < 0) 89 index += buffer->available; 90 91 /* Get row */ 92 buffer_row = &(buffer->rows[index]); 93 94 /* If resizing is needed */ 95 if (width >= buffer_row->length) { 96 97 /* Expand if necessary */ 98 if (width > buffer_row->available) { 99 buffer_row->available = guac_mem_ckd_mul_or_die(width, 2); 100 buffer_row->characters = guac_mem_realloc_or_die(buffer_row->characters, 101 sizeof(guac_terminal_char), buffer_row->available); 102 } 103 104 /* Initialize new part of row */ 105 first = &(buffer_row->characters[buffer_row->length]); 106 for (i=buffer_row->length; i<width; i++) 107 *(first++) = buffer->default_character; 108 109 buffer_row->length = width; 110 111 } 112 113 /* Return found row */ 114 return buffer_row; 115 116} 117 118void guac_terminal_buffer_copy_columns(guac_terminal_buffer* buffer, int row, 119 int start_column, int end_column, int offset) { 120 121 guac_terminal_char* src; 122 guac_terminal_char* dst; 123 124 /* Get row */ 125 guac_terminal_buffer_row* buffer_row = guac_terminal_buffer_get_row(buffer, row, end_column + offset + 1); 126 127 /* Fit range within bounds */ 128 start_column = guac_terminal_fit_to_range(start_column, 0, buffer_row->length - 1); 129 end_column = guac_terminal_fit_to_range(end_column, 0, buffer_row->length - 1); 130 start_column = guac_terminal_fit_to_range(start_column + offset, 0, buffer_row->length - 1) - offset; 131 end_column = guac_terminal_fit_to_range(end_column + offset, 0, buffer_row->length - 1) - offset; 132 133 /* Determine source and destination locations */ 134 src = &(buffer_row->characters[start_column]); 135 dst = &(buffer_row->characters[start_column + offset]); 136 137 /* Copy data */ 138 memmove(dst, src, sizeof(guac_terminal_char) * (end_column - start_column + 1)); 139 140} 141 142void guac_terminal_buffer_copy_rows(guac_terminal_buffer* buffer, 143 int start_row, int end_row, int offset) { 144 145 int i, current_row; 146 int step; 147 148 /* If shifting down, copy in reverse */ 149 if (offset > 0) { 150 current_row = end_row; 151 step = -1; 152 } 153 154 /* Otherwise, copy forwards */ 155 else { 156 current_row = start_row; 157 step = 1; 158 } 159 160 /* Copy each current_row individually */ 161 for (i = start_row; i <= end_row; i++) { 162 163 /* Get source and destination rows */ 164 guac_terminal_buffer_row* src_row = guac_terminal_buffer_get_row(buffer, current_row, 0); 165 guac_terminal_buffer_row* dst_row = guac_terminal_buffer_get_row(buffer, current_row + offset, src_row->length); 166 167 /* Copy data */ 168 memcpy(dst_row->characters, src_row->characters, sizeof(guac_terminal_char) * src_row->length); 169 dst_row->length = src_row->length; 170 171 /* Next current_row */ 172 current_row += step; 173 174 } 175 176} 177 178void guac_terminal_buffer_set_columns(guac_terminal_buffer* buffer, int row, 179 int start_column, int end_column, guac_terminal_char* character) { 180 181 int i, j; 182 guac_terminal_char* current; 183 184 /* Do nothing if glyph is empty */ 185 if (character->width == 0) 186 return; 187 188 /* Build continuation char (for multicolumn characters) */ 189 guac_terminal_char continuation_char; 190 continuation_char.value = GUAC_CHAR_CONTINUATION; 191 continuation_char.attributes = character->attributes; 192 continuation_char.width = 0; /* Not applicable for GUAC_CHAR_CONTINUATION */ 193 194 /* Get and expand row */ 195 guac_terminal_buffer_row* buffer_row = guac_terminal_buffer_get_row(buffer, row, end_column+1); 196 197 /* Set values */ 198 current = &(buffer_row->characters[start_column]); 199 for (i = start_column; i <= end_column; i += character->width) { 200 201 *(current++) = *character; 202 203 /* Store any required continuation characters */ 204 for (j=1; j < character->width; j++) 205 *(current++) = continuation_char; 206 207 } 208 209 /* Update length depending on row written */ 210 if (character->value != 0 && row >= buffer->length) 211 buffer->length = row+1; 212 213} 214