cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

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