#include /* * $Author: tom $ * $Date: 2016/12/04 19:33:34 $ * $Revision: 1.219 $ */ #define L_MARKER '<' #define R_MARKER '>' char *GPasteBuffer = 0; /* * This beeps then flushes the stdout stream. */ void Beep (void) { beep (); fflush (stdout); } /* * This sets a string to the given character. */ void cleanChar (char *s, int len, char character) { if (s != 0) { int x; for (x = 0; x < len; x++) { s[x] = character; } s[--x] = '\0'; } } void cleanChtype (chtype *s, int len, chtype character) { if (s != 0) { int x; for (x = 0; x < len; x++) { s[x] = character; } s[--x] = '\0'; } } /* * This takes an x and y position and realigns the values iff they sent in * values like CENTER, LEFT, RIGHT, ... */ void alignxy (WINDOW *window, int *xpos, int *ypos, int boxWidth, int boxHeight) { int first, gap, last; first = getbegx (window); last = getmaxx (window); if ((gap = (last - boxWidth)) < 0) gap = 0; last = first + gap; switch (*xpos) { case LEFT: (*xpos) = first; break; case RIGHT: (*xpos) = first + gap; break; case CENTER: (*xpos) = first + (gap / 2); break; default: if ((*xpos) > last) (*xpos) = last; else if ((*xpos) < first) (*xpos) = first; break; } first = getbegy (window); last = getmaxy (window); if ((gap = (last - boxHeight)) < 0) gap = 0; last = first + gap; switch (*ypos) { case TOP: (*ypos) = first; break; case BOTTOM: (*ypos) = first + gap; break; case CENTER: (*ypos) = first + (gap / 2); break; default: if ((*ypos) > last) { (*ypos) = last; } else if ((*ypos) < first) { (*ypos) = first; } break; } } /* * This takes a string, a field width and a justification type * and returns the adjustment to make, to fill * the justification requirement. */ int justifyString (int boxWidth, int mesgLength, int justify) { /* * Make sure the message isn't longer than the width. * If it is, return 0. */ if (mesgLength >= boxWidth) return (0); /* Try to justify the message. */ if (justify == LEFT) return (0); if (justify == RIGHT) return boxWidth - mesgLength; if (justify == CENTER) return ((int)((boxWidth - mesgLength) / 2)); return (justify); } /* * This frees a string if it is not null. This is a safety * measure. Some compilers let you free a null string. I * don't like that idea. */ void freeChar (char *string) { freeChecked (string); } void freeChtype (chtype *string) { freeChecked (string); } /* * Corresponding list freeing (does not free the list pointer). */ void freeCharList (char **list, unsigned size) { if (list != 0) { while (size-- != 0) { freeChar (list[size]); list[size] = 0; } } } void freeChtypeList (chtype **list, unsigned size) { if (list != 0) { while (size-- != 0) { freeChtype (list[size]); list[size] = 0; } } } /* * This performs a safe copy of a string. This means it adds the null * terminator on the end of the string, like strdup(). */ char *copyChar (const char *original) { char *newstring = 0; if (original != 0) { if ((newstring = typeMallocN (char, strlen (original) + 1)) != 0) strcpy (newstring, original); } return (newstring); } chtype *copyChtype (const chtype *original) { chtype *newstring = 0; if (original != 0) { int len = chlen (original); if ((newstring = typeMallocN (chtype, len + 4)) != 0) { int x; for (x = 0; x < len; x++) { newstring[x] = original[x]; } newstring[len] = '\0'; newstring[len + 1] = '\0'; } } return (newstring); } /* * Copy the given lists. */ char **copyCharList (const char **list) { size_t size = (size_t) lenCharList (list) + 1; char **result = typeMallocN (char *, size); if (result != 0) { unsigned n; for (n = 0; n < size; ++n) result[n] = copyChar (list[n]); } return result; } chtype **copyChtypeList (const chtype **list) { size_t size = (size_t) lenChtypeList (list) + 1; chtype **result = typeMallocN (chtype *, size); if (result != 0) { unsigned n; for (n = 0; n < size; ++n) result[n] = copyChtype (list[n]); } return result; } /* * Return the length of the given lists. */ int lenCharList (const char **list) { int result = 0; if (list != 0) { while (*list++ != 0) ++result; } return result; } int lenChtypeList (const chtype **list) { int result = 0; if (list != 0) { while (*list++ != 0) ++result; } return result; } /* * This reads a file and sticks it into the char *** provided. */ int CDKreadFile (const char *filename, char ***array) { FILE *fd; char temp[BUFSIZ]; unsigned lines = 0; unsigned used = 0; /* Can we open the file? */ if ((fd = fopen (filename, "r")) == 0) { return (-1); } while ((fgets (temp, sizeof (temp), fd) != 0)) { size_t len = strlen (temp); if (len != 0 && temp[len - 1] == '\n') temp[--len] = '\0'; used = CDKallocStrings (array, temp, lines++, used); } fclose (fd); return (int)(lines); } #define DigitOf(c) ((c)-'0') static int encodeAttribute (const char *string, int from, chtype *mask) { int pair = 0; *mask = 0; switch (string[from + 1]) { case 'B': *mask = A_BOLD; break; case 'D': *mask = A_DIM; break; case 'K': *mask = A_BLINK; break; case 'R': *mask = A_REVERSE; break; case 'S': *mask = A_STANDOUT; break; case 'U': *mask = A_UNDERLINE; break; } if (*mask != 0) { from++; } else { int digits; pair = 0; for (digits = 1; digits <= 3; ++digits) { if (!isdigit (CharOf (string[1 + from]))) break; pair *= 10; pair += DigitOf (string[++from]); } #ifdef HAVE_START_COLOR #define MAX_PAIR (int) (A_COLOR / (((~A_COLOR) << 1) & A_COLOR)) if (pair > MAX_PAIR) pair = MAX_PAIR; *mask = (chtype)COLOR_PAIR (pair); #else *mask = A_BOLD; #endif } return from; } /* * The reverse of encodeAttribute() * Well almost. If attributes such as bold and underline are combined in * the same string, we do not necessarily reconstruct them in the same order. * Also, alignment markers and tabs are lost. */ static unsigned decodeAttribute (char *string, unsigned from, chtype oldattr, chtype newattr) { /* *INDENT-OFF* */ static const struct { int code; chtype mask; } table[] = { { 'B', A_BOLD }, { 'D', A_DIM }, { 'K', A_BLINK }, { 'R', A_REVERSE }, { 'S', A_STANDOUT }, { 'U', A_UNDERLINE }, }; /* *INDENT-ON* */ char temp[80]; char *result = (string != 0) ? string : temp; char *base = result; chtype tmpattr = oldattr & A_ATTRIBUTES; newattr &= A_ATTRIBUTES; if (tmpattr != newattr) { while (tmpattr != newattr) { unsigned n; bool found = FALSE; for (n = 0; n < sizeof (table) / sizeof (table[0]); ++n) { if ((table[n].mask & tmpattr) != (table[n].mask & newattr)) { found = TRUE; *result++ = L_MARKER; if (table[n].mask & tmpattr) { *result++ = '!'; tmpattr &= ~(table[n].mask); } else { *result++ = '/'; tmpattr |= (table[n].mask); } *result++ = (char)table[n].code; break; } } #ifdef HAVE_START_COLOR if ((tmpattr & A_COLOR) != (newattr & A_COLOR)) { int oldpair = PAIR_NUMBER (tmpattr); int newpair = PAIR_NUMBER (newattr); if (!found) { found = TRUE; *result++ = L_MARKER; } if (newpair == 0) { *result++ = '!'; sprintf (result, "%d", oldpair); } else { *result++ = '/'; sprintf (result, "%d", newpair); } result += strlen (result); tmpattr &= ~A_COLOR; newattr &= ~A_COLOR; } #endif if (found) *result++ = R_MARKER; else break; } } return (from + (unsigned)(result - base)); } /* * This function takes a character string, full of format markers * and translates them into a chtype * array. This is better suited * to curses, because curses uses chtype almost exclusively */ chtype *char2Chtype (const char *string, int *to, int *align) { chtype *result = 0; chtype attrib; chtype lastChar; chtype mask; (*to) = 0; *align = LEFT; if (string != 0 && *string != 0) { int len = (int)strlen (string); int pass; int used = 0; /* * We make two passes because we may have indents and tabs to expand, and * do not know in advance how large the result will be. */ for (pass = 0; pass < 2; pass++) { int insideMarker; int from; int adjust; int start; int x = 3; if (pass != 0) { if ((result = typeMallocN (chtype, used + 2)) == 0) { used = 0; break; } } adjust = 0; attrib = A_NORMAL; start = 0; used = 0; /* Look for an alignment marker. */ if (*string == L_MARKER) { if (string[1] == 'C' && string[2] == R_MARKER) { (*align) = CENTER; start = 3; } else if (string[1] == 'R' && string[2] == R_MARKER) { (*align) = RIGHT; start = 3; } else if (string[1] == 'L' && string[2] == R_MARKER) { start = 3; } else if (string[1] == 'B' && string[2] == '=') { /* Set the item index value in the string. */ if (result != 0) { result[0] = ' '; result[1] = ' '; result[2] = ' '; } /* Pull out the bullet marker. */ while (string[x] != R_MARKER && string[x] != 0) { if (result != 0) result[x] = (chtype)string[x] | A_BOLD; x++; } adjust = 1; /* Set the alignment variables. */ start = x; used = x; } else if (string[1] == 'I' && string[2] == '=') { from = 2; x = 0; while (string[++from] != R_MARKER && string[from] != 0) { if (isdigit (CharOf (string[from]))) { adjust = (adjust * 10) + DigitOf (string[from]); x++; } } start = x + 4; } } while (adjust-- > 0) { if (result != 0) result[used] = ' '; used++; } /* Set the format marker boolean to false. */ insideMarker = FALSE; /* Start parsing the character string. */ for (from = start; from < len; from++) { /* Are we inside a format marker? */ if (!insideMarker) { if (string[from] == L_MARKER && (string[from + 1] == '/' || string[from + 1] == '!' || string[from + 1] == '#')) { insideMarker = TRUE; } else if (string[from] == '\\' && string[from + 1] == L_MARKER) { from++; if (result != 0) result[used] = CharOf (string[from]) | attrib; used++; from++; } else if (string[from] == '\t') { do { if (result != 0) result[used] = ' '; used++; } while (used & 7); } else { if (result != 0) result[used] = CharOf (string[from]) | attrib; used++; } } else { switch (string[from]) { case R_MARKER: insideMarker = 0; break; case '#': { lastChar = 0; switch (string[from + 2]) { case 'L': switch (string[from + 1]) { case 'L': lastChar = ACS_LLCORNER; break; case 'U': lastChar = ACS_ULCORNER; break; case 'H': lastChar = ACS_HLINE; break; case 'V': lastChar = ACS_VLINE; break; case 'P': lastChar = ACS_PLUS; break; } break; case 'R': switch (string[from + 1]) { case 'L': lastChar = ACS_LRCORNER; break; case 'U': lastChar = ACS_URCORNER; break; } break; case 'T': switch (string[from + 1]) { case 'T': lastChar = ACS_TTEE; break; case 'R': lastChar = ACS_RTEE; break; case 'L': lastChar = ACS_LTEE; break; case 'B': lastChar = ACS_BTEE; break; } break; case 'A': switch (string[from + 1]) { case 'L': lastChar = ACS_LARROW; break; case 'R': lastChar = ACS_RARROW; break; case 'U': lastChar = ACS_UARROW; break; case 'D': lastChar = ACS_DARROW; break; } break; default: if (string[from + 1] == 'D' && string[from + 2] == 'I') lastChar = ACS_DIAMOND; else if (string[from + 1] == 'C' && string[from + 2] == 'B') lastChar = ACS_CKBOARD; else if (string[from + 1] == 'D' && string[from + 2] == 'G') lastChar = ACS_DEGREE; else if (string[from + 1] == 'P' && string[from + 2] == 'M') lastChar = ACS_PLMINUS; else if (string[from + 1] == 'B' && string[from + 2] == 'U') lastChar = ACS_BULLET; else if (string[from + 1] == 'S' && string[from + 2] == '1') lastChar = ACS_S1; else if (string[from + 1] == 'S' && string[from + 2] == '9') lastChar = ACS_S9; } if (lastChar != 0) { adjust = 1; from += 2; if (string[from + 1] == '(') /* Check for a possible numeric modifier. */ { from++; adjust = 0; while (string[++from] != ')' && string[from] != 0) { if (isdigit (CharOf (string[from]))) { adjust = (adjust * 10) + DigitOf (string[from]); } } } } for (x = 0; x < adjust; x++) { if (result != 0) result[used] = lastChar | attrib; used++; } break; } case '/': from = encodeAttribute (string, from, &mask); attrib = attrib | mask; break; case '!': from = encodeAttribute (string, from, &mask); attrib = attrib & ~mask; break; } } } if (result != 0) { result[used] = 0; result[used + 1] = 0; } /* * If there are no characters, put the attribute into the * the first character of the array. */ if (used == 0 && result != 0) { result[0] = attrib; } } *to = used; } else { /* * Try always to return something; otherwise lists of chtype strings * would get a spurious null pointer whenever there is a blank line, * and CDKfreeChtypes() would fail to free the whole list. */ result = typeCallocN (chtype, 1); } return result; } /* * This determines the length of a chtype string */ int chlen (const chtype *string) { int result = 0; if (string != 0) { while (string[result] != 0) result++; } return (result); } /* * Compare a regular string to a chtype string */ int cmpStrChstr (const char *str, const chtype *chstr) { int r = 0; if (!str && !chstr) return 0; if (!str) return 1; if (!chstr) return -1; while (!r && *str && *chstr) { r = *str - CharOf (*chstr); ++str; ++chstr; } if (r) return r; else if (!*str) return -1; else if (!*chstr) return 1; return 0; } void chstrncpy (char *dest, const chtype *src, int maxcount) { int i = 0; while (i < maxcount && *src) *dest++ = (char)(*src++); *dest = '\0'; } /* * This returns a pointer to char * of a chtype * * Formatting codes are omitted. */ char *chtype2Char (const chtype *string) { char *newstring = 0; if (string != 0) { int len = chlen (string); if ((newstring = typeMallocN (char, len + 1)) != 0) { int x; for (x = 0; x < len; x++) { newstring[x] = (char)CharOf (string[x]); } newstring[len] = '\0'; } } return (newstring); } /* * This returns a pointer to char * of a chtype * * Formatting codes are embedded. */ char *chtype2String (const chtype *string) { char *newstring = 0; if (string != 0) { int pass; int len = chlen (string); for (pass = 0; pass < 2; ++pass) { int x; unsigned need = 0; for (x = 0; x < len; ++x) { need = decodeAttribute (newstring, need, (x > 0) ? string[x - 1] : 0, string[x]); if (newstring != 0) newstring[need] = (char)(string[x]); ++need; } if (pass) newstring[need] = 0; ++need; if (!pass) { if ((newstring = typeMallocN (char, need)) == 0) break; } } } return (newstring); } static int comparSort (const void *a, const void *b) { return strcmp (*(const char *const *)a, (*(const char *const *)b)); } void sortList (CDK_CSTRING *list, int length) { if (length > 1) qsort (list, (unsigned)length, sizeof (list[0]), comparSort); } /* * This strips white space from the given string. */ void stripWhiteSpace (EStripType stripType, char *string) { /* Declare local variables. */ size_t stringLength = 0; /* Make sure the string is not null. */ if (string != 0 && (stringLength = strlen (string)) != 0) { /* Strip leading whitespace */ if (stripType == vFRONT || stripType == vBOTH) { unsigned alphaChar = 0; unsigned x; /* Find the first non-whitespace character. */ while (string[alphaChar] == ' ' || string[alphaChar] == '\t') { alphaChar++; } for (x = alphaChar; x <= stringLength; ++x) string[x - alphaChar] = string[x]; } /* Strip trailing whitespace */ if (stripType == vBACK || stripType == vBOTH) { stringLength = strlen (string); while (stringLength-- != 0 && (string[stringLength] == ' ' || string[stringLength] == '\t')) { string[stringLength] = '\0'; } } } } static unsigned countChar (const char *string, int separator) { unsigned result = 0; int ch; while ((ch = *string++) != 0) { if (ch == separator) result++; } return result; } /* * Split a string into a list of strings. */ char **CDKsplitString (const char *string, int separator) { char **result = 0; char *temp; if (string != 0 && *string != 0) { unsigned need = countChar (string, separator) + 2; if ((result = typeMallocN (char *, need)) != 0) { unsigned item = 0; const char *first = string; for (;;) { while (*string != 0 && *string != separator) string++; need = (unsigned)(string - first); if ((temp = typeMallocN (char, need + 1)) == 0) break; memcpy (temp, first, need); temp[need] = 0; result[item++] = temp; if (*string++ == 0) break; first = string; } result[item] = 0; } } return result; } /* * Add a new string to a list. Keep a null pointer on the end so we can use * CDKfreeStrings() to deallocate the whole list. */ unsigned CDKallocStrings (char ***list, char *item, unsigned length, unsigned used) { unsigned need = 1; while (need < length + 2) need *= 2; if (need > used) { used = need; if (*list == 0) { *list = typeMallocN (char *, used); } else { *list = typeReallocN (char *, *list, used); } } (*list)[length++] = copyChar (item); (*list)[length] = 0; return used; } /* * Count the number of items in a list of strings. */ unsigned CDKcountStrings (CDK_CSTRING2 list) { unsigned result = 0; if (list != 0) { while (*list++ != 0) result++; } return result; } /* * Free a list of strings, terminated by a null pointer. */ void CDKfreeStrings (char **list) { if (list != 0) { void *base = (void *)list; while (*list != 0) free (*list++); free (base); } } /* * Free a list of chtype-strings, terminated by a null pointer. */ void CDKfreeChtypes (chtype **list) { if (list != 0) { void *base = (void *)list; while (*list != 0) { freeChtype (*list++); } free (base); } } int mode2Filetype (mode_t mode) { /* *INDENT-OFF* */ static const struct { mode_t mode; char code; } table[] = { #ifdef S_IFBLK { S_IFBLK, 'b' }, /* Block device */ #endif { S_IFCHR, 'c' }, /* Character device */ { S_IFDIR, 'd' }, /* Directory */ { S_IFREG, '-' }, /* Regular file */ #ifdef S_IFLNK { S_IFLNK, 'l' }, /* Socket */ #endif #ifdef S_IFSOCK { S_IFSOCK, '@' }, /* Socket */ #endif { S_IFIFO, '&' }, /* Pipe */ }; /* *INDENT-ON* */ int filetype = '?'; unsigned n; for (n = 0; n < sizeof (table) / sizeof (table[0]); n++) { if ((mode & S_IFMT) == table[n].mode) { filetype = table[n].code; break; } } return filetype; } /* * This function takes a mode_t type and creates a string represntation * of the permission mode. */ int mode2Char (char *string, mode_t mode) { /* *INDENT-OFF* */ static struct { mode_t mask; unsigned col; char flag; } table[] = { { S_IRUSR, 1, 'r' }, { S_IWUSR, 2, 'w' }, { S_IXUSR, 3, 'x' }, #if defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IXGRP) { S_IRGRP, 4, 'r' }, { S_IWGRP, 5, 'w' }, { S_IXGRP, 6, 'x' }, #endif #if defined (S_IROTH) && defined (S_IWOTH) && defined (S_IXOTH) { S_IROTH, 7, 'r' }, { S_IWOTH, 8, 'w' }, { S_IXOTH, 9, 'x' }, #endif #ifdef S_ISUID { S_ISUID, 3, 's' }, #endif #ifdef S_ISGID { S_ISGID, 6, 's' }, #endif #ifdef S_ISVTX { S_ISVTX, 9, 't' }, #endif }; /* *INDENT-ON* */ /* Declare local variables. */ int permissions = 0; int filetype = mode2Filetype (mode); unsigned n; /* Clean the string. */ cleanChar (string, 11, '-'); string[11] = '\0'; if (filetype == '?') return -1; for (n = 0; n < sizeof (table) / sizeof (table[0]); n++) { if ((mode & table[n].mask) != 0) { string[table[n].col] = table[n].flag; permissions |= (int)table[n].mask; } } /* Check for unusual permissions. */ #ifdef S_ISUID if (((mode & S_IXUSR) == 0) && ((mode & S_IXGRP) == 0) && ((mode & S_IXOTH) == 0) && (mode & S_ISUID) != 0) { string[3] = 'S'; } #endif return permissions; } /* * This returns the length of the integer. */ int intlen (int value) { if (value < 0) return 1 + intlen (-value); else if (value >= 10) return 1 + intlen (value / 10); return 1; } /* * This opens the current directory and reads the contents. */ int CDKgetDirectoryContents (const char *directory, char ***list) { /* Declare local variables. */ struct dirent *dirStruct; int counter = 0; DIR *dp; unsigned used = 0; /* Open the directory. */ dp = opendir (directory); /* Could we open the directory? */ if (dp == 0) { return -1; } /* Read the directory. */ while ((dirStruct = readdir (dp)) != 0) { if (strcmp (dirStruct->d_name, ".")) used = CDKallocStrings (list, dirStruct->d_name, (unsigned)counter++, used); } /* Close the directory. */ closedir (dp); /* Sort the info. */ sortList ((CDK_CSTRING *)*list, counter); /* Return the number of files in the directory. */ return counter; } /* * This looks for a subset of a word in the given list. */ int searchList (CDK_CSTRING2 list, int listSize, const char *pattern) { int Index = -1; /* Make sure the pattern isn't null. */ if (pattern != 0) { size_t len = strlen (pattern); int x; /* Cycle through the list looking for the word. */ for (x = 0; x < listSize; x++) { /* Do a string compare. */ int ret = strncmp (list[x], pattern, len); /* * If 'ret' is less than 0, then the current word is alphabetically * less than the provided word. At this point we will set the index * to the current position. If 'ret' is greater than 0, then the * current word is alphabetically greater than the given word. We * should return with index, which might contain the last best match. * If they are equal, then we've found it. */ if (ret < 0) { Index = ret; } else { if (ret == 0) Index = x; break; } } } return Index; } /* * This function checks to see if a link has been requested. */ int checkForLink (const char *line, char *filename) { int len = 0; int fPos = 0; /* Make sure the line isn't null. */ if (line == 0) { return -1; } len = (int)strlen (line); /* Strip out the filename. */ if (line[0] == L_MARKER && line[1] == 'F' && line[2] == '=') { int x = 3; /* Strip out the filename. */ while (x < len) { if (line[x] == R_MARKER) { break; } if (fPos < CDK_PATHMAX) filename[fPos++] = line[x]; ++x; } } filename[fPos] = '\0'; return (fPos != 0); } /* * Returns the filename portion of the given pathname, i.e., after the last * slash. */ char *baseName (char *pathname) { char *base = 0; if (pathname != 0 && *pathname != '\0' && (base = copyChar (pathname)) != 0) { size_t pathLen; if ((pathLen = strlen (pathname)) != 0) { size_t x; for (x = pathLen - 1; x != 0; --x) { /* Find the last '/' in the pathname. */ if (pathname[x] == '/') { strcpy (base, pathname + x + 1); break; } } } } return base; } /* * Returns the directory for the given pathname, i.e., the part before the * last slash. */ char *dirName (char *pathname) { char *dir = 0; size_t pathLen; /* Check if the string is null. */ if (pathname != 0 && (dir = copyChar (pathname)) != 0 && (pathLen = strlen (pathname)) != 0) { size_t x = pathLen; while ((dir[x] != '/') && (x > 0)) { dir[x--] = '\0'; } } return dir; } /* * If the dimension is a negative value, the dimension will be the full * height/width of the parent window - the value of the dimension. Otherwise, * the dimension will be the given value. */ int setWidgetDimension (int parentDim, int proposedDim, int adjustment) { int dimension = 0; /* If the user passed in FULL, return the parent's size. */ if ((proposedDim == FULL) || (proposedDim == 0)) { dimension = parentDim; } else { /* If they gave a positive value, return it. */ if (proposedDim >= 0) { if (proposedDim >= parentDim) dimension = parentDim; else dimension = (proposedDim + adjustment); } else { /* * If they gave a negative value, then return the * dimension of the parent plus the value given. */ dimension = parentDim + proposedDim; /* Just to make sure. */ if (dimension < 0) dimension = parentDim; } } return dimension; } /* * This safely erases a given window. */ void eraseCursesWindow (WINDOW *window) { if (window != 0) { werase (window); wrefresh (window); } } /* * This safely deletes a given window. */ void deleteCursesWindow (WINDOW *window) { if (window != 0) { eraseCursesWindow (window); delwin (window); } } /* * This moves a given window (if we're able to set the window's beginning). * We do not use mvwin(), because it does (usually) not move subwindows. */ void moveCursesWindow (WINDOW *window, int xdiff, int ydiff) { if (window != 0) { int xpos, ypos; getbegyx (window, ypos, xpos); (void)setbegyx (window, (short)ypos, (short)xpos); xpos += xdiff; ypos += ydiff; werase (window); (void)setbegyx (window, (short)ypos, (short)xpos); } } /* * Return an integer like 'floor()', which returns a double. */ int floorCDK (double value) { int result = (int)value; if (result > value) /* e.g., value < 0.0 and value is not an integer */ result--; return result; } /* * Return an integer like 'ceil()', which returns a double. */ int ceilCDK (double value) { return -floorCDK (-value); } /* * Compatibility for different versions of curses. */ #if !(defined(HAVE_GETBEGX) && defined(HAVE_GETBEGY)) int getbegx (WINDOW *win) { int y, x; getbegyx (win, y, x); return x; } int getbegy (WINDOW *win) { int y, x; getbegyx (win, y, x); return y; } #endif #if !(defined(HAVE_GETMAXX) && defined(HAVE_GETMAXY)) int getmaxx (WINDOW *win) { int y, x; getmaxyx (win, y, x); return x; } int getmaxy (WINDOW *win) { int y, x; getmaxyx (win, y, x); return y; } #endif