blob: f8851696a89155b218d6c6dfef4f85a753da58f2 [file] [log] [blame] [edit]
/*
* BRLTTY - A background process providing access to the console screen (when in
* text mode) for a blind person using a refreshable braille display.
*
* Copyright (C) 1995-2023 by The BRLTTY Developers.
*
* BRLTTY comes with ABSOLUTELY NO WARRANTY.
*
* This is free software, placed under the terms of the
* GNU Lesser General Public License, as published by the Free Software
* Foundation; either version 2.1 of the License, or (at your option) any
* later version. Please see the file LICENSE-LGPL for details.
*
* Web Page: http://brltty.app/
*
* This software is maintained by Dave Mielke <dave@mielke.cc>.
*/
#include "prologue.h"
/* Source file for range list management module */
/* For a description of what each function does, see rangelist.h */
#include <stdio.h>
#include "brlapi_keyranges.h"
#include "log.h"
static int inKeyrange(KeyrangeList *l, KeyrangeElem e)
{
uint32_t flags = KeyrangeFlags(e);
uint32_t val = KeyrangeVal(e);
return (l->minVal <= val && val <= l->maxVal && (flags | l->minFlags) == flags && ((flags & ~l->maxFlags) == 0));
}
/* Function : createKeyrange */
static KeyrangeList **createKeyrange(KeyrangeList **p, uint32_t minFlags, uint32_t minVal, uint32_t maxFlags, uint32_t maxVal, KeyrangeList *n)
{
KeyrangeList *c = malloc(sizeof(KeyrangeList));
if (c==NULL) return NULL;
c->minFlags = minFlags; c->minVal = minVal;
c->maxFlags = maxFlags; c->maxVal = maxVal;
c->next = n;
*p = c;
return &c->next;
}
/* Function : freeKeyrange */
static void freeKeyrange(KeyrangeList **p, KeyrangeList *c)
{
if (c==NULL) return;
*p = c->next;
free(c);
}
/* Function : freeKeyrangeList */
void freeKeyrangeList(KeyrangeList **l)
{
KeyrangeList *p1, *p2;
if (l==NULL) return;
p2 = *l;
while (p2!=NULL) {
p1 = p2;
p2 = p1->next;
free(p1);
}
*l = NULL;
}
/* Function : inKeyrangeList */
KeyrangeList *inKeyrangeList(KeyrangeList *l, KeyrangeElem n)
{
KeyrangeList *c = l;
while (c!=NULL) {
if (inKeyrange(c, n)) return c;
c = c->next;
}
return NULL;
}
/* Function : DisplayKeyrangeList */
void DisplayKeyrangeList(KeyrangeList *l)
{
if (l==NULL) printf("emptyset");
else {
KeyrangeList *c = l;
while (1) {
printf("[%lx(%lx)..%lx(%lx)]",(unsigned long)c->minVal,(unsigned long)c->minFlags,(unsigned long)c->maxVal,(unsigned long)c->maxFlags);
if (c->next==NULL) break;
printf(",");
c = c->next;
}
}
printf("\n");
}
/* Function : addKeyrange */
int addKeyrange(KeyrangeElem x0, KeyrangeElem y0, KeyrangeList **l)
{
KeyrangeList *c;
uint32_t minFlags = KeyrangeFlags(x0) & KeyrangeFlags(y0);
uint32_t maxFlags = KeyrangeFlags(x0) | KeyrangeFlags(y0);
uint32_t minVal = MIN(KeyrangeVal(x0), KeyrangeVal(y0));
uint32_t maxVal = MAX(KeyrangeVal(x0), KeyrangeVal(y0));
KeyrangeElem min = KeyrangeElem(minFlags, minVal);
KeyrangeElem max = KeyrangeElem(maxFlags, maxVal);
logMessage(LOG_CATEGORY(SERVER_EVENTS) | LOG_DEBUG,
"adding range [%"PRIx32"(%"PRIx32")..%"PRIx32"(%"PRIx32")]",
minVal, minFlags, maxVal, maxFlags
);
c = *l;
while (c) {
if (inKeyrange(c, min) && inKeyrange(c, max))
/* Falls completely within an existing range */
return 0;
if (c->minVal <= maxVal && maxVal <= c->maxVal && minFlags == c->minFlags && maxFlags == c->maxFlags) {
/* May just change lower bound */
/* Note that minVal can't be >= c->minVal */
c->minVal = minVal;
return 0;
}
if (c->minVal <= minVal && minVal <= c->maxVal && minFlags == c->minFlags && maxFlags == c->maxFlags) {
/* May just change upper bound */
/* Note that maxVal can't be <= c->maxVal */
c->maxVal = maxVal;
return 0;
}
c = c->next;
}
/* Else things are not easy, just add */
if ((createKeyrange(l,minFlags,minVal,maxFlags,maxVal,*l)) == NULL) return -1;
return 0;
}
int removeKeyrange(KeyrangeElem x0, KeyrangeElem y0, KeyrangeList **l)
{
uint32_t minFlags = KeyrangeFlags(x0) & KeyrangeFlags(y0);
uint32_t maxFlags = KeyrangeFlags(x0) | KeyrangeFlags(y0);
uint32_t minVal = MIN(KeyrangeVal(x0), KeyrangeVal(y0));
uint32_t maxVal = MAX(KeyrangeVal(x0), KeyrangeVal(y0));
KeyrangeList *c, **p, *tmp;
if ((l==NULL) || (*l==NULL)) return 0;
logMessage(LOG_CATEGORY(SERVER_EVENTS) | LOG_DEBUG,
"removing range [%"PRIx32"(%"PRIx32")..%"PRIx32"(%"PRIx32")]",
minVal, minFlags, maxVal, maxFlags
);
/* Need to intersect with every range */
p = l; c = *p;
while (c) {
if (c->minVal > maxVal || c->maxVal < minVal ||
!(c->maxFlags | ~minFlags) || !(~c->minFlags | maxFlags)) {
/* don't intersect */
p = &c->next;
c = *p;
continue;
}
if (minVal <= c->minVal && maxVal >= c->maxVal &&
(c->minFlags | minFlags) == c->minFlags &&
(c->maxFlags & ~maxFlags) == 0) {
/* range falls completely in deletion range, just drop it */
tmp = c; c = c->next;
freeKeyrange(p,tmp);
continue;
}
/* Partly intersect */
if (c->minVal < minVal) {
/* lower part should be kept intact, save it. */
p = createKeyrange(p, c->minFlags, c->minVal, c->maxFlags, minVal - 1, c);
if (p == NULL) return -1;
c->minVal = minVal;
}
if (c->maxVal > maxVal) {
/* upper part should be kept intact, save it. */
p = createKeyrange(p, c->minFlags, maxVal + 1, c->maxFlags, c->maxVal, c);
if (p == NULL) return -1;
c->maxVal = maxVal;
}
/* Now values are contained in suppression, intersect against flags */
if (~minFlags & maxFlags) {
/* At least some flag must now be neither cleared nor set, drop range */
tmp = c; c = c->next;
freeKeyrange(p,tmp);
continue;
}
/* Clamp flags on the value interval */
c->minFlags |= ~maxFlags;
c->maxFlags &= ~minFlags;
p = &c->next;
c = *p;
}
return 0;
}