/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "config.h" #include "terminal/buffer.h" #include "terminal/common.h" #include #include guac_terminal_buffer* guac_terminal_buffer_alloc(int rows, guac_terminal_char* default_character) { /* Allocate scrollback */ guac_terminal_buffer* buffer = malloc(sizeof(guac_terminal_buffer)); int i; guac_terminal_buffer_row* row; /* Init scrollback data */ buffer->default_character = *default_character; buffer->available = rows; buffer->top = 0; buffer->length = 0; buffer->rows = malloc(sizeof(guac_terminal_buffer_row) * buffer->available); /* Init scrollback rows */ row = buffer->rows; for (i=0; iavailable = 256; row->length = 0; row->characters = malloc(sizeof(guac_terminal_char) * row->available); /* Next row */ row++; } return buffer; } void guac_terminal_buffer_free(guac_terminal_buffer* buffer) { int i; guac_terminal_buffer_row* row = buffer->rows; /* Free all rows */ for (i=0; iavailable; i++) { free(row->characters); row++; } /* Free actual buffer */ free(buffer->rows); free(buffer); } guac_terminal_buffer_row* guac_terminal_buffer_get_row(guac_terminal_buffer* buffer, int row, int width) { int i; guac_terminal_char* first; guac_terminal_buffer_row* buffer_row; /* Normalize row index into a scrollback buffer index */ int index = (buffer->top + row) % buffer->available; if (index < 0) index += buffer->available; /* Get row */ buffer_row = &(buffer->rows[index]); /* If resizing is needed */ if (width >= buffer_row->length) { /* Expand if necessary */ if (width > buffer_row->available) { buffer_row->available = width*2; buffer_row->characters = realloc(buffer_row->characters, sizeof(guac_terminal_char) * buffer_row->available); } /* Initialize new part of row */ first = &(buffer_row->characters[buffer_row->length]); for (i=buffer_row->length; idefault_character; buffer_row->length = width; } /* Return found row */ return buffer_row; } void guac_terminal_buffer_copy_columns(guac_terminal_buffer* buffer, int row, int start_column, int end_column, int offset) { guac_terminal_char* src; guac_terminal_char* dst; /* Get row */ guac_terminal_buffer_row* buffer_row = guac_terminal_buffer_get_row(buffer, row, end_column + offset + 1); /* Fit range within bounds */ start_column = guac_terminal_fit_to_range(start_column, 0, buffer_row->length - 1); end_column = guac_terminal_fit_to_range(end_column, 0, buffer_row->length - 1); start_column = guac_terminal_fit_to_range(start_column + offset, 0, buffer_row->length - 1) - offset; end_column = guac_terminal_fit_to_range(end_column + offset, 0, buffer_row->length - 1) - offset; /* Determine source and destination locations */ src = &(buffer_row->characters[start_column]); dst = &(buffer_row->characters[start_column + offset]); /* Copy data */ memmove(dst, src, sizeof(guac_terminal_char) * (end_column - start_column + 1)); } void guac_terminal_buffer_copy_rows(guac_terminal_buffer* buffer, int start_row, int end_row, int offset) { int i, current_row; int step; /* If shifting down, copy in reverse */ if (offset > 0) { current_row = end_row; step = -1; } /* Otherwise, copy forwards */ else { current_row = start_row; step = 1; } /* Copy each current_row individually */ for (i = start_row; i <= end_row; i++) { /* Get source and destination rows */ guac_terminal_buffer_row* src_row = guac_terminal_buffer_get_row(buffer, current_row, 0); guac_terminal_buffer_row* dst_row = guac_terminal_buffer_get_row(buffer, current_row + offset, src_row->length); /* Copy data */ memcpy(dst_row->characters, src_row->characters, sizeof(guac_terminal_char) * src_row->length); dst_row->length = src_row->length; /* Next current_row */ current_row += step; } } void guac_terminal_buffer_set_columns(guac_terminal_buffer* buffer, int row, int start_column, int end_column, guac_terminal_char* character) { int i, j; guac_terminal_char* current; /* Do nothing if glyph is empty */ if (character->width == 0) return; /* Build continuation char (for multicolumn characters) */ guac_terminal_char continuation_char; continuation_char.value = GUAC_CHAR_CONTINUATION; continuation_char.attributes = character->attributes; continuation_char.width = 0; /* Not applicable for GUAC_CHAR_CONTINUATION */ /* Get and expand row */ guac_terminal_buffer_row* buffer_row = guac_terminal_buffer_get_row(buffer, row, end_column+1); /* Set values */ current = &(buffer_row->characters[start_column]); for (i = start_column; i <= end_column; i += character->width) { *(current++) = *character; /* Store any required continuation characters */ for (j=1; j < character->width; j++) *(current++) = continuation_char; } /* Update length depending on row written */ if (character->value != 0 && row >= buffer->length) buffer->length = row+1; }