Logo Search packages:      
Sourcecode: zephyr version File versions  Download package

formatter.c

/* This file is part of the Project Athena Zephyr Notification System.
 * It is one of the source files comprising zwgc, the Zephyr WindowGram
 * client.
 *
 *      Created by:     Marc Horowitz <marc@athena.mit.edu>
 *
 *      $Id: formatter.c,v 1.15 1999/01/22 23:20:20 ghudson Exp $
 *
 *      Copyright (c) 1989 by the Massachusetts Institute of Technology.
 *      For copying and distribution information, see the file
 *      "mit-copyright.h".
 */

#include <sysdep.h>

#if (!defined(lint) && !defined(SABER))
static const char rcsid_formatter_c[] = "$Id: formatter.c,v 1.15 1999/01/22 23:20:20 ghudson Exp $";
#endif

#include <zephyr/mit-copyright.h>
#include <zephyr/zephyr.h>

#include "new_memory.h"
#include "char_stack.h"
#include "string_dictionary.h"
#include "formatter.h"
#include "text_operations.h"

#if !defined(__STDC__) && !defined(const)
#define const
#endif

static int pure_text_length(), env_length();

#ifdef notdef
static character_class atsign_set = { /* '@' = 0x40 */
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  };
#endif

static const character_class paren_set = { /* '(' = 0x28, ')' = 0x29 */
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  };

static const character_class sbracket_set = { /* '[' = 0x5b, ']' = 0x5d */
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  };

static const character_class abracket_set = { /* '<' = 0x3c, '>' = 0x3e */
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  };

static const character_class cbracket_set = { /* '{' = 0x7b, '}' = 0x7d */
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  };

static const character_class allbracket_set = {
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  };

static const character_class allmaskable_set = {
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,
   1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  };

static char brackets[]="()<>[]{}@";
static char *openbracket[]={"@<","@<","@[","@[","@{","@{","@(","@(","@("};
static char *closebracket[]={">",">","]","]","}","}",")",")",")"};

static int not_contains(str, set)
     string str;
     const character_class set;
{
   while (*str && ! set[*str]) str++;
   return (! *str);
}

static int pure_text_length(text,terminator)
     char *text;
     char terminator;
{
   int len=0;

   while (1) {
      while (*text!='@' && *text!=terminator && *text) {
         text++;
         len++;
      }

      if (*text!='@')
         return(len);

      if (*(text+1)=='@') {
       text++;
       len++;
      } else if (env_length(text+1) != -1)
        return(len);

      text++;
      len++;
   }
}

static char otherside(opener)
char opener;
{
   switch (opener) {
    case '(':
      return(')');
    case '{':
      return('}');
    case '[':
      return(']');
    case '<':
      return('>');
   }

#ifdef DEBUG
   abort();
#endif
}

/* the char * that str points to is free'd by this function.
 * if you want to keep it, save it yourself
 */
string verbatim(str, bracketsonly)
     string str;
     int bracketsonly;
{
   char *temp,*temp2;
   int bracketnum,len;

   if (strlen(str) == pure_text_length(str,0)) {
      /* No environments, so consider the fast-and-easy methods */

      if (not_contains(str,allbracket_set)) {
       temp = string_Copy(str);
       free(str);
       return(temp);
      }

      if (not_contains(str,abracket_set)) {
       temp=(char *) malloc((len=strlen(str))+4);
       temp[0]='@';
       temp[1]='<';
       (void) memcpy(temp+2,str,len);
       temp[len+2]='>';
       temp[len+3]='\0';
       free(str);
       return(temp);
      }
      if (not_contains(str,sbracket_set)) {
       temp=(char *) malloc((len=strlen(str))+4);
       temp[0]='@';
       temp[1]='[';
       (void) memcpy(temp+2,str,len);
       temp[len+2]=']';
       temp[len+3]='\0';
       free(str);
       return(temp);
      }
      if (not_contains(str,cbracket_set)) {
       temp=(char *) malloc((len=strlen(str))+4);
       temp[0]='@';
       temp[1]='{';
       (void) memcpy(temp+2,str,len);
       temp[len+2]='}';
       temp[len+3]='\0';
       free(str);
       return(temp);
      }
      if (not_contains(str,paren_set)) {
       temp=(char *) malloc((len=strlen(str))+4);
       temp[0]='@';
       temp[1]='(';
       (void) memcpy(temp+2,str,len);
       temp[len+2]=')';
       temp[len+3]='\0';
       free(str);
       return(temp);
      }
   }

   temp=lbreak(&str,bracketsonly?allbracket_set:allmaskable_set);
   while(*str) {
      bracketnum=(int) (strchr(brackets,str[0])-brackets);
      temp=string_Concat2(temp,openbracket[bracketnum]);
      temp=string_Concat2(temp,temp2=lany(&str," "));
      free(temp2);
      temp=string_Concat2(temp,closebracket[bracketnum]);
      temp=string_Concat2(temp,temp2=lbreak(&str,bracketsonly?
                                allbracket_set:allmaskable_set));
      free(temp2);
   }
   free(str);  /* str is "" at this point, anyway */

   return(temp);
}

/* text points to beginning of text string.  return value is
   length of string, up to but not including the passed terminator
   or the default terminator \0.  The text will not be modified,
   and @@ will be counted twice */

string protect(str)
     string str;
{
   string temp,temp2,temp3;
   int len,templen;
   char_stack chs;
   char tos;

   temp = string_Copy("");
   templen = 1;
   chs = char_stack_create();

   while(*str) {
      tos = (char_stack_empty(chs)?0:char_stack_top(chs));

      if (*str == tos) {
       /* if the character is the next terminator */

       temp = (char *) realloc(temp,++templen);
       temp[templen-2] = *str++;
       char_stack_pop(chs);
       temp[templen-1] = '\0';
      } else if (len = pure_text_length(str,tos)) {
       if (tos) {
          /* if the block is text in an environment, just copy it */

          temp2 = string_CreateFromData(str,len);
          str += len;
          temp = string_Concat2(temp,temp2);
          templen += len;
          free(temp2);
       } else {
          /* if the block is top level text, verbatim brackets only
             (not @'s) and add text to temp */

          temp2 = string_CreateFromData(str,len);
          str += len;
          temp3 = verbatim(temp2,1);
          temp = string_Concat2(temp,temp3);
          templen += strlen(temp3);
          free(temp3);
       }
      } else {
       /* if the block is an environment, copy it, push delimiter */

       len = env_length(str+1);
       char_stack_push(chs,otherside(str[len+1]));
       len += 2;
       temp2 = string_CreateFromData(str,len);
       str += len;
       temp = string_Concat2(temp,temp2);
       templen += len;
       free(temp2);
      }
   }
   /* all blocks have been copied. */

   while (!char_stack_empty(chs)) {
      temp = (char *) realloc(temp,++templen);
      temp[templen-2] = char_stack_top(chs);
      char_stack_pop(chs);
   }
   temp[templen-1] = '\0';

   return(temp);
}

/* str points to a string.  return value is another string
   which is the original with all styles removed. */
string stylestrip(str)
     string str;
{
    int templen = 0, otherchar;
    char *temp = (char *) malloc(string_Length(str) + 1);
    char_stack chs;
    string ostr = str;

    chs = char_stack_create();

    while (*str) {
      if (*str == '@') {
          int len = env_length(str + 1);
          if (len != -1) {
            otherchar = 0;
            if ((len == 4 && !strncasecmp(str + 1, "font", 4))
              || (len == 5 && !strncasecmp(str + 1, "color", 5)))
                otherchar = 0x80;
            otherchar |= otherside(str[len + 1]);
            char_stack_push(chs, otherchar);
            str += len + 2;
            continue;
          }
      }
      if (!char_stack_empty(chs) && *str == (char_stack_top(chs) & 0x7f)) {
          char_stack_pop(chs);
          str++;
          continue;
      }
      if (!char_stack_empty(chs) && (char_stack_top(chs) & 0x80))
          str++;
      else
          temp[templen++] = *str++;
    }
    temp[templen] = 0;

    while (!char_stack_empty(chs))
      char_stack_pop(chs);
    free(ostr);

    return(temp);
}

void free_desc(desc)
     desctype *desc;
{
    desctype *next_desc;

    while (desc->code != DT_EOF) {
      next_desc = desc->next;
      free(desc);
      desc = next_desc;
    }
    free(desc);
}

/* text points to beginning of possible env name.  return value is
   length of env name, not including @ or opener, or -1 if not a
   possible env name. */
static int env_length(text)
     char *text;
{
   int len=0;

   while (*text && (isalnum(*text) || *text=='_')) {
      text++;
      len++;
   }

   if ((*text=='(') || (*text=='{') || (*text=='[') || (*text=='<'))
     return(len);
   else
     return(-1);
}

/* text points to beginning of text string.  return value is
   length of string, up to but not including the passed terminator
   or the default terminators \0 \n @.  This can modify text, and 0
   is a valid return value. */
static int text_length(text,terminator)
     char *text;
     char terminator;
{
   int len=0;

   while (1) {
      while (*text!='@' && *text!='\n' && *text!=terminator && *text) {
       text++;
       len++;
      }

      if (*text!='@')
       return(len);

      if (*(text+1)=='@')
       (void) memmove(text+1,text+2,strlen(text+1));
      else if (env_length(text+1) != -1)
      return(len);

      text++;
      len++;
   }
}

/* parses str into a desc linked list.  Returns number of strings and
   newlines in *pstr and *pnl */

desctype *disp_get_cmds(str,pstr,pnl)
char *str;
int *pstr,*pnl;
{
   desctype *desc,*here;
   int len;
   char_stack terminators = char_stack_create();
   char terminator;
   int nstr=0, nnl=0;
   char *curstr;

   desc=(desctype *) malloc(sizeof(desctype));
   here=desc;
   curstr=str;
   terminator = '\0';

   while (*curstr) {
      if (*curstr=='\n') {
       here->code=DT_NL;
       curstr++;
       nnl++;
      } else if (*curstr==terminator) { /* if this is the end of an env */
       here->code=DT_END;
       terminator = char_stack_top(terminators);
       char_stack_pop(terminators);
       curstr++;
      } else if (len=text_length(curstr,terminator)) { /* if there is a text
                                            block here */
       here->code=DT_STR;
       here->str=curstr;
       here->len=len;
       curstr+=len;
       nstr++;
      } else if (*curstr=='@') { /* if this is the beginning of an env */
       len=env_length(curstr+1);
       here->code=DT_ENV;
       here->str=curstr+1;
       here->len=len;
       char_stack_push(terminators, terminator);
       terminator=otherside(*(curstr+1+len));
       curstr+=(len+2); /* jump over @, env name, and opener */
      }

      here->next=(desctype *) malloc(sizeof(desctype));
      here=here->next;
   }

   while (!char_stack_empty(terminators)) {
      here->code=DT_END;
      terminator = char_stack_top(terminators);
      char_stack_pop(terminators);
      here->next=(desctype *) malloc(sizeof(desctype));
      here=here->next;
   }
   here->code=DT_EOF;
   *pstr=nstr;
   *pnl=nnl;

#ifdef DEBUG_PRINTOUT
   { string temp;
       here = desc;
       while (here->code != DT_EOF) {
         if (here->code == DT_STR || here->code == DT_ENV) {
             temp = string_CreateFromData(here->str, here->len);
             printf("[%d <%s>]\n", here->code, temp);
             free(temp);
         } else
           printf("[%d]\n", here->code);
         here=here->next;
       }
 }
#endif

   return(desc);
}

Generated by  Doxygen 1.6.0   Back to index