Changeset 9e219d3
- Timestamp:
- Mar 13, 2016, 12:43:12 PM (8 years ago)
- Children:
- ed05467
- Parents:
- 0f5af62
- git-author:
- Karl Ramm <kcr@1ts.org> (03/12/16 21:40:02)
- git-committer:
- Karl Ramm <kcr@1ts.org> (03/13/16 12:43:12)
- Files:
-
- 2 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
AUTHORS
r80c0fc7 r9e219d3 32 32 Betsy Riley 33 33 Robert Jacobs 34 Google Inc. 34 35 35 36 BarnOwl is based on code from Owl, which was originally primarily -
Makefile.am
rca1fb26a r9e219d3 56 56 CODELIST_SRCS=message.c mainwin.c popwin.c zephyr.c messagelist.c \ 57 57 commands.c global.c text.c fmtext.c editwin.c \ 58 util.c logging.c \58 util.c logging.c ztext.c \ 59 59 perlconfig.c keys.c functions.c zwrite.c viewwin.c help.c filter.c \ 60 60 regex.c history.c view.c dict.c variable.c filterelement.c pair.c \ -
fmtext.c
rf271129 r9e219d3 549 549 } 550 550 551 /* flattens a ztext parse tree into fmtext */ 552 static void owl_fmtext_append_ztext_tree(owl_fmtext *f, ztext_env *tree, char attr, short fg) 553 { 554 char *s; 555 int i; 556 bool handled = false; 557 const struct { 558 const char *tag; 559 const char mask; 560 } TAGS[] = { 561 {"", 0}, 562 {"@", 0}, 563 {"@bold", OWL_FMTEXT_ATTR_BOLD}, 564 {"@b", OWL_FMTEXT_ATTR_BOLD}, 565 {"@italic", OWL_FMTEXT_ATTR_UNDERLINE}, 566 {"@i", OWL_FMTEXT_ATTR_UNDERLINE}, 567 {NULL, 0}, 568 }; 569 570 if (tree->closer == '@' && tree->content == NULL) { 571 owl_fmtext_append_attr(f, "@", attr, fg, OWL_COLOR_DEFAULT); 572 return; 573 } 574 575 for (i = 0; TAGS[i].tag != NULL; i++) { 576 if (!strcasecmp(tree->label, TAGS[i].tag)) { 577 attr |= TAGS[i].mask; 578 handled = true; 579 break; 580 } 581 } 582 583 if (!handled) { 584 /* continue the dubious practice of printing codes we don't understand */ 585 s = g_strdup_printf("%s%c", tree->label, tree->opener); 586 owl_fmtext_append_attr(f, s, attr, fg, OWL_COLOR_DEFAULT); 587 g_free(s); 588 } 589 590 for (ztext_node *p = tree->content; p != NULL; p = p->next) { 591 if (p->type == ZTEXT_NODE_STRING) { 592 owl_fmtext_append_attr(f, p->string, attr, fg, OWL_COLOR_DEFAULT); 593 } else if (p->type == ZTEXT_NODE_ENV) { 594 if (!strcasecmp(p->env->label, "@color")) { 595 s = ztext_strip(p->env); 596 fg = owl_util_string_to_color(s); 597 if (fg == OWL_COLOR_INVALID) 598 fg = OWL_COLOR_DEFAULT; 599 g_free(s); 600 } else { 601 owl_fmtext_append_ztext_tree(f, p->env, attr, fg); 602 } 603 } 604 } 605 606 if (!handled) { 607 s = g_strdup_printf("%c", tree->closer); 608 owl_fmtext_append_attr(f, s, attr, fg, OWL_COLOR_DEFAULT); 609 g_free(s); 610 } 611 } 551 612 552 613 /* Append the text 'text' to 'f' and interpret the zephyr style … … 555 616 void owl_fmtext_append_ztext(owl_fmtext *f, const char *text) 556 617 { 557 int stacksize, curattrs, curcolor; 558 const char *ptr, *txtptr, *tmpptr; 559 char *buff; 560 int attrstack[32], chrstack[32], colorstack[32]; 561 562 curattrs=OWL_FMTEXT_ATTR_NONE; 563 curcolor=OWL_COLOR_DEFAULT; 564 stacksize=0; 565 txtptr=text; 566 while (1) { 567 ptr=strpbrk(txtptr, "@{[<()>]}"); 568 if (!ptr) { 569 /* add all the rest of the text and exit */ 570 owl_fmtext_append_attr(f, txtptr, curattrs, curcolor, OWL_COLOR_DEFAULT); 571 return; 572 } else if (ptr[0]=='@') { 573 /* add the text up to this point then deal with the stack */ 574 buff=g_new(char, ptr-txtptr+20); 575 strncpy(buff, txtptr, ptr-txtptr); 576 buff[ptr-txtptr]='\0'; 577 owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT); 578 g_free(buff); 579 580 /* update pointer to point at the @ */ 581 txtptr=ptr; 582 583 /* now the stack */ 584 585 /* if we've hit our max stack depth, print the @ and move on */ 586 if (stacksize==32) { 587 owl_fmtext_append_attr(f, "@", curattrs, curcolor, OWL_COLOR_DEFAULT); 588 txtptr++; 589 continue; 590 } 591 592 /* if it's an @@, print an @ and continue */ 593 if (txtptr[1]=='@') { 594 owl_fmtext_append_attr(f, "@", curattrs, curcolor, OWL_COLOR_DEFAULT); 595 txtptr+=2; 596 continue; 597 } 598 599 /* if there's no opener, print the @ and continue */ 600 tmpptr=strpbrk(txtptr, "(<[{ "); 601 if (!tmpptr || tmpptr[0]==' ') { 602 owl_fmtext_append_attr(f, "@", curattrs, curcolor, OWL_COLOR_DEFAULT); 603 txtptr++; 604 continue; 605 } 606 607 /* check what command we've got, push it on the stack, start 608 using it, and continue ... unless it's a color command */ 609 buff=g_new(char, tmpptr-ptr+20); 610 strncpy(buff, ptr, tmpptr-ptr); 611 buff[tmpptr-ptr]='\0'; 612 if (!strcasecmp(buff, "@bold")) { 613 attrstack[stacksize]=OWL_FMTEXT_ATTR_BOLD; 614 chrstack[stacksize]=tmpptr[0]; 615 colorstack[stacksize]=curcolor; 616 stacksize++; 617 curattrs|=OWL_FMTEXT_ATTR_BOLD; 618 txtptr+=6; 619 g_free(buff); 620 continue; 621 } else if (!strcasecmp(buff, "@b")) { 622 attrstack[stacksize]=OWL_FMTEXT_ATTR_BOLD; 623 chrstack[stacksize]=tmpptr[0]; 624 colorstack[stacksize]=curcolor; 625 stacksize++; 626 curattrs|=OWL_FMTEXT_ATTR_BOLD; 627 txtptr+=3; 628 g_free(buff); 629 continue; 630 } else if (!strcasecmp(buff, "@i")) { 631 attrstack[stacksize]=OWL_FMTEXT_ATTR_UNDERLINE; 632 chrstack[stacksize]=tmpptr[0]; 633 colorstack[stacksize]=curcolor; 634 stacksize++; 635 curattrs|=OWL_FMTEXT_ATTR_UNDERLINE; 636 txtptr+=3; 637 g_free(buff); 638 continue; 639 } else if (!strcasecmp(buff, "@italic")) { 640 attrstack[stacksize]=OWL_FMTEXT_ATTR_UNDERLINE; 641 chrstack[stacksize]=tmpptr[0]; 642 colorstack[stacksize]=curcolor; 643 stacksize++; 644 curattrs|=OWL_FMTEXT_ATTR_UNDERLINE; 645 txtptr+=8; 646 g_free(buff); 647 continue; 648 } else if (!strcasecmp(buff, "@")) { 649 attrstack[stacksize]=OWL_FMTEXT_ATTR_NONE; 650 chrstack[stacksize]=tmpptr[0]; 651 colorstack[stacksize]=curcolor; 652 stacksize++; 653 txtptr+=2; 654 g_free(buff); 655 continue; 656 657 /* if it's a color read the color, set the current color and 658 continue */ 659 } else if (!strcasecmp(buff, "@color") 660 && owl_global_is_colorztext(&g)) { 661 g_free(buff); 662 txtptr+=7; 663 tmpptr=strpbrk(txtptr, "@{[<()>]}"); 664 if (tmpptr && 665 ((txtptr[-1]=='(' && tmpptr[0]==')') || 666 (txtptr[-1]=='<' && tmpptr[0]=='>') || 667 (txtptr[-1]=='[' && tmpptr[0]==']') || 668 (txtptr[-1]=='{' && tmpptr[0]=='}'))) { 669 670 /* grab the color name */ 671 buff=g_new(char, tmpptr-txtptr+20); 672 strncpy(buff, txtptr, tmpptr-txtptr); 673 buff[tmpptr-txtptr]='\0'; 674 675 /* set it as the current color */ 676 curcolor=owl_util_string_to_color(buff); 677 if (curcolor == OWL_COLOR_INVALID) 678 curcolor = OWL_COLOR_DEFAULT; 679 g_free(buff); 680 txtptr=tmpptr+1; 681 continue; 682 683 } else { 684 685 } 686 687 } else { 688 /* if we didn't understand it, we'll print it. This is different from zwgc 689 * but zwgc seems to be smarter about some screw cases than I am 690 */ 691 g_free(buff); 692 owl_fmtext_append_attr(f, "@", curattrs, curcolor, OWL_COLOR_DEFAULT); 693 txtptr++; 694 continue; 695 } 696 697 } else if (ptr[0]=='}' || ptr[0]==']' || ptr[0]==')' || ptr[0]=='>') { 698 /* add the text up to this point first */ 699 buff=g_new(char, ptr-txtptr+20); 700 strncpy(buff, txtptr, ptr-txtptr); 701 buff[ptr-txtptr]='\0'; 702 owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT); 703 g_free(buff); 704 705 /* now deal with the closer */ 706 txtptr=ptr; 707 708 /* first, if the stack is empty we must bail (just print and go) */ 709 if (stacksize==0) { 710 buff=g_new(char, 5); 711 buff[0]=ptr[0]; 712 buff[1]='\0'; 713 owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT); 714 g_free(buff); 715 txtptr++; 716 continue; 717 } 718 719 /* if the closing char is what's on the stack, turn off the 720 attribue and pop the stack */ 721 if ((ptr[0]==')' && chrstack[stacksize-1]=='(') || 722 (ptr[0]=='>' && chrstack[stacksize-1]=='<') || 723 (ptr[0]==']' && chrstack[stacksize-1]=='[') || 724 (ptr[0]=='}' && chrstack[stacksize-1]=='{')) { 725 int i; 726 stacksize--; 727 curattrs=OWL_FMTEXT_ATTR_NONE; 728 curcolor = colorstack[stacksize]; 729 for (i=0; i<stacksize; i++) { 730 curattrs|=attrstack[i]; 731 } 732 txtptr+=1; 733 continue; 734 } else { 735 /* otherwise print and continue */ 736 buff=g_new(char, 5); 737 buff[0]=ptr[0]; 738 buff[1]='\0'; 739 owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT); 740 g_free(buff); 741 txtptr++; 742 continue; 743 } 744 } else { 745 /* we've found an unattached opener, print everything and move on */ 746 buff=g_new(char, ptr-txtptr+20); 747 strncpy(buff, txtptr, ptr-txtptr+1); 748 buff[ptr-txtptr+1]='\0'; 749 owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT); 750 g_free(buff); 751 txtptr=ptr+1; 752 continue; 753 } 754 } 755 } 618 ztext_env *tree = ztext_tree(text); 619 620 owl_fmtext_append_ztext_tree(f, tree, 621 OWL_FMTEXT_ATTR_NONE, OWL_COLOR_DEFAULT); 622 623 ztext_env_free(tree); 624 } 625 756 626 757 627 /* requires that the list values are strings or NULL. -
owl.h
rca1fb26a r9e219d3 63 63 64 64 #include "window.h" 65 #include "ztext.h" 65 66 66 67 extern const char *version; -
tester.c
r21dc927 r9e219d3 26 26 int call_filter_regtest(void); 27 27 int owl_smartstrip_regtest(void); 28 int ztext_test(void); 28 29 29 30 extern void owl_perl_xs_init(pTHX); … … 118 119 numfailures += call_filter_regtest(); 119 120 numfailures += owl_smartstrip_regtest(); 121 numfailures += ztext_test(); 120 122 if (numfailures) { 121 123 fprintf(stderr, "# *** WARNING: %d failures total\n", numfailures); … … 1055 1057 return numfailed; 1056 1058 } 1059 1060 static char *ztext_str(ztext_env *tree) 1061 { 1062 /* Unambiguous representation of the parse tree */ 1063 char *s, *t, *u; 1064 1065 if (tree->opener) { 1066 s = g_strdup_printf("{'%s%c'", tree->label, tree->opener); 1067 } else { 1068 s = g_strdup("{-"); 1069 } 1070 1071 for (ztext_node *p = tree->content; p != NULL; p = p->next) { 1072 t = s; 1073 if (p->type== ZTEXT_NODE_STRING) { 1074 s = g_strdup_printf("%s |%s|", s, p->string); 1075 } else if (p->type == ZTEXT_NODE_ENV) { 1076 u = ztext_str(p->env); 1077 s = g_strconcat(s, " ", u, NULL); 1078 g_free(u); 1079 } 1080 g_free(t); 1081 } 1082 1083 t = s; 1084 if (tree->closer) { 1085 s = g_strdup_printf("%s '%c'}", s, tree->closer); 1086 } else { 1087 s = g_strconcat(s, "}", NULL); 1088 } 1089 g_free(t); 1090 1091 return s; 1092 } 1093 1094 char *ztext_ztext(ztext_env *tree) 1095 { 1096 char *s, *t, *u; 1097 1098 if (tree->closer == '@' && tree->content == NULL) 1099 return g_strdup("@@"); 1100 1101 if (tree->opener) { 1102 s = g_strdup_printf("%s%c", tree->label, tree->opener); 1103 } else { 1104 s = g_strdup(""); 1105 } 1106 1107 for (ztext_node *p = tree->content; p != NULL; p = p->next) { 1108 t = s; 1109 if (p->type == ZTEXT_NODE_STRING) { 1110 s = g_strconcat(s, p->string, NULL); 1111 } else if (p->type == ZTEXT_NODE_ENV) { 1112 u = ztext_ztext(p->env); 1113 s = g_strconcat(s, u, NULL); 1114 g_free(u); 1115 } 1116 g_free(t); 1117 } 1118 1119 if (tree->closer) { 1120 t = s; 1121 s = g_strdup_printf("%s%c", s, tree->closer); 1122 g_free(t); 1123 } 1124 1125 return s; 1126 } 1127 1128 int ztext_test(void) 1129 { 1130 int numfailed = 0; 1131 char *s; 1132 ztext_env *t; 1133 char *d; 1134 1135 #define CHECK_ZTEXT_STR(in, expected) \ 1136 do { \ 1137 t = ztext_tree(in); \ 1138 s = ztext_str(t); \ 1139 d = g_strdup_printf("ztext decode \"%s\" expected \"%s\" got \"%s\"", \ 1140 in, expected, s); \ 1141 FAIL_UNLESS(d, !strcmp(s, expected)); \ 1142 ztext_env_free(t); \ 1143 g_free(d); \ 1144 g_free(s); \ 1145 } while (0) 1146 1147 CHECK_ZTEXT_STR("", "{-}"); 1148 CHECK_ZTEXT_STR("foo", "{- |foo|}"); 1149 CHECK_ZTEXT_STR("@{foo}", "{- {'@{' |foo| '}'}}"); 1150 CHECK_ZTEXT_STR("@bar{foo}", "{- {'@bar{' |foo| '}'}}"); 1151 CHECK_ZTEXT_STR("@bar{foo@bar}", "{- {'@bar{' |foo@bar| '}'}}"); 1152 CHECK_ZTEXT_STR("@bar{foo@@bar}", "{- {'@bar{' |foo| {'@@' '@'} |bar| '}'}}"); 1153 CHECK_ZTEXT_STR("@{foo@}bar}baz", "{- {'@{' |foo@| '}'} |bar}baz|}"); 1154 CHECK_ZTEXT_STR("foo@bar{baz@(bang})}", 1155 "{- |foo| {'@bar{' |baz| {'@(' |bang}| ')'} '}'}}"); 1156 CHECK_ZTEXT_STR("foo@bar{baz}", "{- |foo| {'@bar{' |baz| '}'}}"); 1157 CHECK_ZTEXT_STR("@bloop", "{- |@bloop|}"); 1158 1159 #define CHECK_ZTEXT_STRIP(in, expected) \ 1160 do { \ 1161 t = ztext_tree(in); \ 1162 s = ztext_strip(t); \ 1163 d = g_strdup_printf("ztext strip \"%s\" expected \"%s\" got \"%s\"", \ 1164 in, expected, s); \ 1165 FAIL_UNLESS(d, !strcmp(s, expected)); \ 1166 ztext_env_free(t); \ 1167 g_free(d); \ 1168 g_free(s); \ 1169 } while (0) 1170 1171 CHECK_ZTEXT_STRIP("", ""); 1172 CHECK_ZTEXT_STRIP("foo", "foo"); 1173 CHECK_ZTEXT_STRIP("@{foo}", "foo"); 1174 CHECK_ZTEXT_STRIP("@bar{foo}", "foo"); 1175 CHECK_ZTEXT_STRIP("@bar{foo@bar}", "foo@bar"); 1176 CHECK_ZTEXT_STRIP("@bar{foo@@bar}", "foo@bar"); 1177 CHECK_ZTEXT_STRIP("@{foo@}bar}baz", "foo@bar}baz"); 1178 CHECK_ZTEXT_STRIP("foo@bar{baz@(bang})}", "foobazbang}"); 1179 CHECK_ZTEXT_STRIP("foo@bar{baz}", "foobaz"); 1180 CHECK_ZTEXT_STRIP("@bloop", "@bloop"); 1181 1182 #define CHECK_ZTEXT_RT(in) \ 1183 do { \ 1184 t = ztext_tree(in); \ 1185 s = ztext_ztext(t); \ 1186 d = g_strdup_printf("ztext round-trip \"%s\" got \"%s\"", in, s); \ 1187 FAIL_UNLESS(d, !strcmp(s, in)); \ 1188 ztext_env_free(t); \ 1189 g_free(s); \ 1190 } while (0) 1191 1192 CHECK_ZTEXT_RT(""); 1193 CHECK_ZTEXT_RT("foo"); 1194 CHECK_ZTEXT_RT("@{foo}"); 1195 CHECK_ZTEXT_RT("@bar{foo}"); 1196 CHECK_ZTEXT_RT("@bar{foo@bar}"); 1197 CHECK_ZTEXT_RT("@bar{foo@@bar}"); 1198 CHECK_ZTEXT_RT("@{foo@}bar}baz"); 1199 CHECK_ZTEXT_RT("foo@bar{baz@(bang})}"); 1200 CHECK_ZTEXT_RT("foo@bar{baz}"); 1201 CHECK_ZTEXT_RT("@bloop"); 1202 1203 /* fuzzzzzz */ 1204 srand48(getpid() + time(0)); 1205 1206 char tango[32]; 1207 const char CHARS[] = "@abc ({<[]>})"; 1208 1209 for(int i=0; i < 1000; i++) { 1210 memset(tango, 0, sizeof(tango)); 1211 int l = lrand48() % sizeof(tango); 1212 for (int j=0; j < l; j++) { 1213 tango[j] = CHARS[lrand48() % (sizeof(CHARS) -1)]; 1214 } 1215 CHECK_ZTEXT_RT(tango); 1216 } 1217 1218 1219 return numfailed; 1220 }
Note: See TracChangeset
for help on using the changeset viewer.