]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zwgc/formatter.c
c900c9fa95cc11fd9d0b51856f4e255ca48fc05a
[1ts-debian.git] / zephyr / zwgc / formatter.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It is one of the source files comprising zwgc, the Zephyr WindowGram
3  * client.
4  *
5  *      Created by:     Marc Horowitz <marc@athena.mit.edu>
6  *
7  *      $Id$
8  *
9  *      Copyright (c) 1989 by the Massachusetts Institute of Technology.
10  *      For copying and distribution information, see the file
11  *      "mit-copyright.h".
12  */
13
14 #include <sysdep.h>
15
16 #if (!defined(lint) && !defined(SABER))
17 static const char rcsid_formatter_c[] = "$Id$";
18 #endif
19
20 #include <zephyr/mit-copyright.h>
21 #include <zephyr/zephyr.h>
22
23 #include "new_memory.h"
24 #include "char_stack.h"
25 #include "string_dictionary.h"
26 #include "formatter.h"
27 #include "text_operations.h"
28
29 #if !defined(__STDC__) && !defined(const)
30 #define const
31 #endif
32
33 static int pure_text_length(), env_length();
34
35 #ifdef notdef
36 static character_class atsign_set = { /* '@' = 0x40 */
37    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
38    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
39    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
40    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
41    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
42    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
43    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
44    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
45    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
46    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
47    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
48    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
49    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
50    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
51    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
52    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
53   };
54 #endif
55
56 static const character_class paren_set = { /* '(' = 0x28, ')' = 0x29 */
57    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
58    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
59    0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
60    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
61    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
62    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
63    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
64    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
65    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
66    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
67    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
68    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
69    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
70    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
71    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
72    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
73   };
74
75 static const character_class sbracket_set = { /* '[' = 0x5b, ']' = 0x5d */
76    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
77    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
78    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
79    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
80    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
81    0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
82    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
83    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
84    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
85    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
86    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
87    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
88    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
89    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
90    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
91    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
92   };
93
94 static const character_class abracket_set = { /* '<' = 0x3c, '>' = 0x3e */
95    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
96    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
97    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
98    0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,
99    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
100    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
101    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
102    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
103    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
104    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
105    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
106    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
107    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
108    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
109    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
110    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
111   };
112
113 static const character_class cbracket_set = { /* '{' = 0x7b, '}' = 0x7d */
114    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
115    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
116    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
117    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
118    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
119    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
120    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
121    0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
122    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
123    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
124    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
125    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
126    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
127    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
128    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
129    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
130   };
131
132 static const character_class allbracket_set = {
133    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
134    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
135    0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
136    0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,
137    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
138    0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
139    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
140    0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
141    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
142    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
143    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
144    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
145    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
146    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
147    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
148    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
149   };
150
151 static const character_class allmaskable_set = {
152    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
153    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
154    0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
155    0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,
156    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
157    0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
158    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
159    0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
160    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
161    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
162    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
163    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
164    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
165    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
166    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
167    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
168   };
169
170 static char brackets[]="()<>[]{}@";
171 static char *openbracket[]={"@<","@<","@[","@[","@{","@{","@(","@(","@("};
172 static char *closebracket[]={">",">","]","]","}","}",")",")",")"};
173
174 static int not_contains(str, set)
175      string str;
176      const character_class set;
177 {
178    while (*str && ! set[*str]) str++;
179    return (! *str);
180 }
181
182 static int pure_text_length(text,terminator)
183      char *text;
184      char terminator;
185 {
186    int len=0;
187
188    while (1) {
189       while (*text!='@' && *text!=terminator && *text) {
190          text++;
191          len++;
192       }
193
194       if (*text!='@')
195          return(len);
196
197       if (*(text+1)=='@') {
198          text++;
199          len++;
200       } else if (env_length(text+1) != -1)
201         return(len);
202
203       text++;
204       len++;
205    }
206 }
207
208 static char otherside(opener)
209 char opener;
210 {
211    switch (opener) {
212     case '(':
213       return(')');
214     case '{':
215       return('}');
216     case '[':
217       return(']');
218     case '<':
219       return('>');
220    }
221
222 #ifdef DEBUG
223    abort();
224 #endif
225 }
226
227 /* the char * that str points to is free'd by this function.
228  * if you want to keep it, save it yourself
229  */
230 string verbatim(str, bracketsonly)
231      string str;
232      int bracketsonly;
233 {
234    char *temp,*temp2;
235    int bracketnum,len;
236
237    if (strlen(str) == pure_text_length(str,0)) {
238       /* No environments, so consider the fast-and-easy methods */
239
240       if (not_contains(str,allbracket_set)) {
241          temp = string_Copy(str);
242          free(str);
243          return(temp);
244       }
245
246       if (not_contains(str,abracket_set)) {
247          temp=(char *) malloc((len=strlen(str))+4);
248          temp[0]='@';
249          temp[1]='<';
250          (void) memcpy(temp+2,str,len);
251          temp[len+2]='>';
252          temp[len+3]='\0';
253          free(str);
254          return(temp);
255       }
256       if (not_contains(str,sbracket_set)) {
257          temp=(char *) malloc((len=strlen(str))+4);
258          temp[0]='@';
259          temp[1]='[';
260          (void) memcpy(temp+2,str,len);
261          temp[len+2]=']';
262          temp[len+3]='\0';
263          free(str);
264          return(temp);
265       }
266       if (not_contains(str,cbracket_set)) {
267          temp=(char *) malloc((len=strlen(str))+4);
268          temp[0]='@';
269          temp[1]='{';
270          (void) memcpy(temp+2,str,len);
271          temp[len+2]='}';
272          temp[len+3]='\0';
273          free(str);
274          return(temp);
275       }
276       if (not_contains(str,paren_set)) {
277          temp=(char *) malloc((len=strlen(str))+4);
278          temp[0]='@';
279          temp[1]='(';
280          (void) memcpy(temp+2,str,len);
281          temp[len+2]=')';
282          temp[len+3]='\0';
283          free(str);
284          return(temp);
285       }
286    }
287
288    temp=lbreak(&str,bracketsonly?allbracket_set:allmaskable_set);
289    while(*str) {
290       bracketnum=(int) (strchr(brackets,str[0])-brackets);
291       temp=string_Concat2(temp,openbracket[bracketnum]);
292       temp=string_Concat2(temp,temp2=lany(&str," "));
293       free(temp2);
294       temp=string_Concat2(temp,closebracket[bracketnum]);
295       temp=string_Concat2(temp,temp2=lbreak(&str,bracketsonly?
296                                           allbracket_set:allmaskable_set));
297       free(temp2);
298    }
299    free(str);  /* str is "" at this point, anyway */
300
301    return(temp);
302 }
303
304 /* text points to beginning of text string.  return value is
305    length of string, up to but not including the passed terminator
306    or the default terminator \0.  The text will not be modified,
307    and @@ will be counted twice */
308
309 string protect(str)
310      string str;
311 {
312    string temp,temp2,temp3;
313    int len,templen;
314    char_stack chs;
315    char tos;
316
317    temp = string_Copy("");
318    templen = 1;
319    chs = char_stack_create();
320
321    while(*str) {
322       tos = (char_stack_empty(chs)?0:char_stack_top(chs));
323
324       if (*str == tos) {
325          /* if the character is the next terminator */
326
327          temp = (char *) realloc(temp,++templen);
328          temp[templen-2] = *str++;
329          char_stack_pop(chs);
330          temp[templen-1] = '\0';
331       } else if (len = pure_text_length(str,tos)) {
332          if (tos) {
333             /* if the block is text in an environment, just copy it */
334
335             temp2 = string_CreateFromData(str,len);
336             str += len;
337             temp = string_Concat2(temp,temp2);
338             templen += len;
339             free(temp2);
340          } else {
341             /* if the block is top level text, verbatim brackets only
342                (not @'s) and add text to temp */
343
344             temp2 = string_CreateFromData(str,len);
345             str += len;
346             temp3 = verbatim(temp2,1);
347             temp = string_Concat2(temp,temp3);
348             templen += strlen(temp3);
349             free(temp3);
350          }
351       } else {
352          /* if the block is an environment, copy it, push delimiter */
353
354          len = env_length(str+1);
355          char_stack_push(chs,otherside(str[len+1]));
356          len += 2;
357          temp2 = string_CreateFromData(str,len);
358          str += len;
359          temp = string_Concat2(temp,temp2);
360          templen += len;
361          free(temp2);
362       }
363    }
364    /* all blocks have been copied. */
365
366    while (!char_stack_empty(chs)) {
367       temp = (char *) realloc(temp,++templen);
368       temp[templen-2] = char_stack_top(chs);
369       char_stack_pop(chs);
370    }
371    temp[templen-1] = '\0';
372
373    return(temp);
374 }
375
376 /* str points to a string.  return value is another string
377    which is the original with all styles removed. */
378 string stylestrip(str)
379      string str;
380 {
381     int templen = 0, otherchar;
382     char *temp = (char *) malloc(string_Length(str) + 1);
383     char_stack chs;
384     string ostr = str;
385
386     chs = char_stack_create();
387
388     while (*str) {
389         if (*str == '@') {
390             int len = env_length(str + 1);
391             if (len != -1) {
392                 otherchar = 0;
393                 if ((len == 4 && !strncasecmp(str + 1, "font", 4))
394                   || (len == 5 && !strncasecmp(str + 1, "color", 5)))
395                     otherchar = 0x80;
396                 otherchar |= otherside(str[len + 1]);
397                 char_stack_push(chs, otherchar);
398                 str += len + 2;
399                 continue;
400             }
401         }
402         if (!char_stack_empty(chs) && *str == (char_stack_top(chs) & 0x7f)) {
403             char_stack_pop(chs);
404             str++;
405             continue;
406         }
407         if (!char_stack_empty(chs) && (char_stack_top(chs) & 0x80))
408             str++;
409         else
410             temp[templen++] = *str++;
411     }
412     temp[templen] = 0;
413
414     while (!char_stack_empty(chs))
415         char_stack_pop(chs);
416     free(ostr);
417
418     return(temp);
419 }
420
421 void free_desc(desc)
422      desctype *desc;
423 {
424     desctype *next_desc;
425
426     while (desc->code != DT_EOF) {
427         next_desc = desc->next;
428         free(desc);
429         desc = next_desc;
430     }
431     free(desc);
432 }
433
434 /* text points to beginning of possible env name.  return value is
435    length of env name, not including @ or opener, or -1 if not a
436    possible env name. */
437 static int env_length(text)
438      char *text;
439 {
440    int len=0;
441
442    while (*text && (isalnum(*text) || *text=='_')) {
443       text++;
444       len++;
445    }
446
447    if ((*text=='(') || (*text=='{') || (*text=='[') || (*text=='<'))
448      return(len);
449    else
450      return(-1);
451 }
452
453 /* text points to beginning of text string.  return value is
454    length of string, up to but not including the passed terminator
455    or the default terminators \0 \n @.  This can modify text, and 0
456    is a valid return value. */
457 static int text_length(text,terminator)
458      char *text;
459      char terminator;
460 {
461    int len=0;
462
463    while (1) {
464       while (*text!='@' && *text!='\n' && *text!=terminator && *text) {
465          text++;
466          len++;
467       }
468
469       if (*text!='@')
470          return(len);
471
472       if (*(text+1)=='@')
473          (void) memmove(text+1,text+2,strlen(text+1));
474       else if (env_length(text+1) != -1)
475         return(len);
476
477       text++;
478       len++;
479    }
480 }
481
482 /* parses str into a desc linked list.  Returns number of strings and
483    newlines in *pstr and *pnl */
484
485 desctype *disp_get_cmds(str,pstr,pnl)
486 char *str;
487 int *pstr,*pnl;
488 {
489    desctype *desc,*here;
490    int len;
491    char_stack terminators = char_stack_create();
492    char terminator;
493    int nstr=0, nnl=0;
494    char *curstr;
495
496    desc=(desctype *) malloc(sizeof(desctype));
497    here=desc;
498    curstr=str;
499    terminator = '\0';
500
501    while (*curstr) {
502       if (*curstr=='\n') {
503          here->code=DT_NL;
504          curstr++;
505          nnl++;
506       } else if (*curstr==terminator) { /* if this is the end of an env */
507          here->code=DT_END;
508          terminator = char_stack_top(terminators);
509          char_stack_pop(terminators);
510          curstr++;
511       } else if (len=text_length(curstr,terminator)) { /* if there is a text
512                                                           block here */
513          here->code=DT_STR;
514          here->str=curstr;
515          here->len=len;
516          curstr+=len;
517          nstr++;
518       } else if (*curstr=='@') { /* if this is the beginning of an env */
519          len=env_length(curstr+1);
520          here->code=DT_ENV;
521          here->str=curstr+1;
522          here->len=len;
523          char_stack_push(terminators, terminator);
524          terminator=otherside(*(curstr+1+len));
525          curstr+=(len+2); /* jump over @, env name, and opener */
526       }
527
528       here->next=(desctype *) malloc(sizeof(desctype));
529       here=here->next;
530    }
531
532    while (!char_stack_empty(terminators)) {
533       here->code=DT_END;
534       terminator = char_stack_top(terminators);
535       char_stack_pop(terminators);
536       here->next=(desctype *) malloc(sizeof(desctype));
537       here=here->next;
538    }
539    here->code=DT_EOF;
540    *pstr=nstr;
541    *pnl=nnl;
542
543 #ifdef DEBUG_PRINTOUT
544    { string temp;
545        here = desc;
546        while (here->code != DT_EOF) {
547            if (here->code == DT_STR || here->code == DT_ENV) {
548                temp = string_CreateFromData(here->str, here->len);
549                printf("[%d <%s>]\n", here->code, temp);
550                free(temp);
551            } else
552              printf("[%d]\n", here->code);
553            here=here->next;
554        }
555  }
556 #endif
557
558    return(desc);
559 }