/* misc.c -- Eterm toolkit routines * This file is original work by Michael Jennings and * Tuomo Venalainen . This file, and any other file * bearing this same message or a similar one, is distributed under * the GNU Public License (GPL) as outlined in the COPYING file. * * Copyright (C) 1997, Michael Jennings and Tuomo Venalainen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ static const char cvs_ident[] = "$Id$"; #include "config.h" #include "feature.h" #include #include #include #include #include #include "../libmej/debug.h" #include "debug.h" #include "../libmej/mem.h" #include "../libmej/strings.h" #include "command.h" #include "main.h" #include "misc.h" #include "options.h" const char * my_basename(const char *str) { const char *base = strrchr(str, '/'); return (base ? base + 1 : str); } /* Print a non-terminal error message */ void print_error(const char *fmt,...) { va_list arg_ptr; va_start(arg_ptr, fmt); fprintf(stderr, APL_NAME ": "); vfprintf(stderr, fmt, arg_ptr); fprintf(stderr, "\n"); va_end(arg_ptr); } /* Print a simple warning. */ void print_warning(const char *fmt,...) { va_list arg_ptr; va_start(arg_ptr, fmt); fprintf(stderr, APL_NAME ": warning: "); vfprintf(stderr, fmt, arg_ptr); fprintf(stderr, "\n"); va_end(arg_ptr); } /* Print a fatal error message and terminate */ void fatal_error(const char *fmt,...) { va_list arg_ptr; va_start(arg_ptr, fmt); fprintf(stderr, APL_NAME ": FATAL: "); vfprintf(stderr, fmt, arg_ptr); fprintf(stderr, "\n"); va_end(arg_ptr); exit(-1); } /* * Compares the first n characters of s1 and s2, where n is strlen(s2) * Returns strlen(s2) if they match, 0 if not. */ unsigned long str_leading_match(register const char *s1, register const char *s2) { register unsigned long n; if (!s1 || !s2) { return (0); } for (n = 0; *s2; n++, s1++, s2++) { if (*s1 != *s2) { return 0; } } return n; } /* Strip leading and trailing whitespace and quotes from a string */ char * str_trim(char *str) { register char *tmp = str; size_t n; if (str && *str) { chomp(str); n = strlen(str); if (!n) { *str = 0; return str; } /* strip leading/trailing quotes */ if (*tmp == '"') { tmp++; n--; if (!n) { *str = 0; return str; } else if (tmp[n - 1] == '"') { tmp[--n] = '\0'; } } if (tmp != str) { memmove(str, tmp, (strlen(tmp)) + 1); } } return str; } /* * in-place interpretation of string: * * backslash-escaped: "\a\b\E\e\n\r\t", "\octal" * Ctrl chars: ^@ .. ^_, ^? * * Emacs-style: "M-" prefix * * Also, * "M-x" prefixed strings, append "\r" if needed * "\E]" prefixed strings (XTerm escape sequence) append "\a" if needed * * returns the converted string length */ int parse_escaped_string(char *str) { register char *pold, *pnew; unsigned char i; D_STRINGS(("parse_escaped_string(\"%s\")\n", str)); for (pold = pnew = str; *pold; pold++, pnew++) { D_STRINGS(("Looking at \"%s\"\n", pold)); if (!BEG_STRCASECMP(pold, "m-")) { *pold = '\\'; *(pold + 1) = 'e'; } else if (!BEG_STRCASECMP(pold, "c-")) { *(++pold) = '^'; } D_STRINGS(("Operating on \'%c\'\n", *pold)); switch (*pold) { case '\\': D_STRINGS(("Backslash + %c\n", *(pold + 1))); switch (tolower(*(++pold))) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': for (i = 0; *pold >= '0' && *pold <= '7'; pold++) { i = (i * 8) + (*pold - '0'); } pold--; D_STRINGS(("Octal number evaluates to %d\n", i)); *pnew = i; break; case 'n': *pnew = '\n'; break; case 'r': *pnew = '\r'; break; case 't': *pnew = '\t'; break; case 'b': *pnew = '\b'; break; case 'f': *pnew = '\f'; break; case 'a': *pnew = '\a'; break; case 'v': *pnew = '\v'; break; case 'e': *pnew = '\033'; break; case 'c': pold++; *pnew = MAKE_CTRL_CHAR(*pold); break; default: *pnew = *pold; break; } break; case '^': D_STRINGS(("Caret + %c\n", *(pold + 1))); pold++; *pnew = MAKE_CTRL_CHAR(*pold); break; default: *pnew = *pold; } } if (!BEG_STRCASECMP(str, "\033x") && *(pnew - 1) != '\r') { D_STRINGS(("Adding carriage return\n")); *(pnew++) = '\r'; } else if (!BEG_STRCASECMP(str, "\e]") && *(pnew - 1) != '\a') { D_STRINGS(("Adding bell character\n")); *(pnew++) = '\a'; } *pnew = 0; #if DEBUG >= DEBUG_STRINGS if (debug_level >= DEBUG_STRINGS) { D_STRINGS(("New value is:\n\n")); HexDump(str, (size_t) (pnew - str)); } #endif return (pnew - str); } const char * find_file(const char *file, const char *ext) { const char *f; #if defined(PIXMAP_SUPPORT) if ((f = search_path(rs_path, file, ext)) != NULL) { return (f); } else if ((f = search_path(getenv(PATH_ENV), file, ext)) != NULL) { return (f); } else { return (search_path(initial_dir, file, ext)); } #else return ((const char *) NULL); #endif } /*----------------------------------------------------------------------* * miscellaneous drawing routines */ /* * draw bottomShadow/highlight along top/left sides of the window */ void Draw_tl(Window win, GC gc, int x, int y, int w, int h) { int shadow = SHADOW; if (w == 0 || h == 0) { shadow = 1; } w += (x - 1); h += (y - 1); for (; shadow > 0; shadow--, x++, y++, w--, h--) { XDrawLine(Xdisplay, win, gc, x, y, w, y); XDrawLine(Xdisplay, win, gc, x, y, x, h); } } /* * draw bottomShadow/highlight along the bottom/right sides of the window */ void Draw_br(Window win, GC gc, int x, int y, int w, int h) { int shadow = SHADOW; if (w == 0 || h == 0) { shadow = 1; } w += (x - 1); h += (y - 1); x++; y++; for (; shadow > 0; shadow--, x++, y++, w--, h--) { XDrawLine(Xdisplay, win, gc, w, h, w, y); XDrawLine(Xdisplay, win, gc, w, h, x, h); } } void Draw_Shadow(Window win, GC topShadow, GC botShadow, int x, int y, int w, int h) { Draw_tl(win, topShadow, x, y, w, h); Draw_br(win, botShadow, x, y, w, h); } /* button shapes */ void Draw_Triangle(Window win, GC topShadow, GC botShadow, int x, int y, int w, int type) { switch (type) { case 'r': /* right triangle */ XDrawLine(Xdisplay, win, topShadow, x, y, x, y + w); XDrawLine(Xdisplay, win, topShadow, x, y, x + w, y + w / 2); XDrawLine(Xdisplay, win, botShadow, x, y + w, x + w, y + w / 2); break; case 'l': /* left triangle */ XDrawLine(Xdisplay, win, botShadow, x + w, y + w, x + w, y); XDrawLine(Xdisplay, win, botShadow, x + w, y + w, x, y + w / 2); XDrawLine(Xdisplay, win, topShadow, x, y + w / 2, x + w, y); break; case 'd': /* down triangle */ XDrawLine(Xdisplay, win, topShadow, x, y, x + w / 2, y + w); XDrawLine(Xdisplay, win, topShadow, x, y, x + w, y); XDrawLine(Xdisplay, win, botShadow, x + w, y, x + w / 2, y + w); break; case 'u': /* up triangle */ XDrawLine(Xdisplay, win, botShadow, x + w, y + w, x + w / 2, y); XDrawLine(Xdisplay, win, botShadow, x + w, y + w, x, y + w); XDrawLine(Xdisplay, win, topShadow, x, y + w, x + w / 2, y); break; #if 0 case 's': /* square */ XDrawLine(Xdisplay, win, topShadow, x + w, y, x, y); XDrawLine(Xdisplay, win, topShadow, x, y, x, y + w); XDrawLine(Xdisplay, win, botShadow, x, y + w, x + w, y + w); XDrawLine(Xdisplay, win, botShadow, x + w, y + w, x + w, y); break; #endif } }