Merge branch 'gtk3'
[projects/chimara/chimara.git] / babel / ifiction.c
diff --git a/babel/ifiction.c b/babel/ifiction.c
deleted file mode 100644 (file)
index cb620e7..0000000
+++ /dev/null
@@ -1,534 +0,0 @@
-/* ifiction.c  common babel interface for processing ifiction metadata\r
- * (c) 2006 By L. Ross Raszewski\r
- *\r
- * This code is freely usable for all purposes.\r
- *\r
- * This work is licensed under the Creative Commons Attribution2.5 License.\r
- * To view a copy of this license, visit\r
- * http://creativecommons.org/licenses/by/2.5/ or send a letter to\r
- * Creative Commons,\r
- * 543 Howard Street, 5th Floor,\r
- * San Francisco, California, 94105, USA.\r
- *\r
- * This file depends on treaty.h\r
- *\r
- * This file contains common routines for handling ifiction metadata strings\r
- *\r
- * int32 ifiction_get_IFID(char *metadata, char *output, int32 output_extent)\r
- * does what the babel treaty function GET_STORY_FILE_IFID_SEL would do for ifiction\r
- *\r
- * void ifiction_parse(char *md, IFCloseTag close_tag, void *close_ctx,\r
- *                     IFErrorHandler error_handler, void *error_ctx)\r
- * parses the given iFiction metadata.  close_tag(struct XMLtag xtg, close_ctx)\r
- * is called for each tag as it is closed, error_handler(char *error, error_ctx)\r
- * is called each time a structural or logical error is found in the iFiction\r
- * This is a very simple XML parser, and probably not as good as any "real"\r
- * XML parser.  Its only two benefits are that (1) it's really small, and (2)\r
- * it strictly checks the ifiction record against the Treaty of Babel\r
- * requirements\r
- *\r
- */\r
-\r
-#include "ifiction.h"\r
-#include <string.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <ctype.h>\r
-\r
-void *my_malloc(int, char *);\r
-extern char *format_registry[];\r
-\r
-\r
-static int32 llp;\r
-static char *lnlst;\r
-\r
-static char utfeol[3] = { 0xe2, 0x80, 0xa8 };\r
-static int32 getln(char *endp)\r
-{\r
- for(;lnlst<endp;lnlst++) if (*lnlst=='\n' || memcmp(lnlst,utfeol,3)==0) llp++;\r
- return llp;\r
-}\r
-\r
-\r
-static int32 ifiction_get_first_IFID(char *metadata, char *output, int32 output_extent)\r
-{\r
- char *ifid_begin, *ifid_end;\r
\r
- ifid_begin=strstr(metadata,"<ifid>");\r
- if (!ifid_begin) return NO_REPLY_RV;\r
- ifid_begin+=6;\r
-\r
- ifid_end=strstr(ifid_begin,"</ifid>");\r
- if (!ifid_end) return NO_REPLY_RV;\r
- if (output_extent<=(ifid_end-ifid_begin)) return INVALID_USAGE_RV;\r
-\r
- memcpy(output,ifid_begin,ifid_end-ifid_begin);\r
-\r
- output[ifid_end-ifid_begin]=0;\r
-\r
- return ifid_end-metadata+7;\r
-}\r
-\r
-\r
-int32 ifiction_get_IFID(char *metadata, char *output, int32 output_extent)\r
-{\r
- int32 j=0, k;\r
-\r
- while(*metadata)\r
- {\r
- if ((k=ifiction_get_first_IFID(metadata,output,output_extent)) <= 0) break;\r
- j++;\r
- metadata+=k;\r
- output_extent-=strlen(output)+1;\r
- output+=strlen(output);\r
- *output=',';\r
- output++;\r
- }\r
- if (*(output-1)==',') *(output-1)=0;\r
- return j;\r
-}\r
-\r
-\r
-static char *leaf_tags[] = { "ifid",\r
-                             "format",\r
-                             "bafn",\r
-                             "title",\r
-                             "author",\r
-                             "headline",\r
-                             "firstpublished",\r
-                             "genre",\r
-                             "group",\r
-                             "description",\r
-                             "leafname",\r
-                             "url",\r
-                             "authoremail",\r
-                             "height",\r
-                             "width",\r
-\r
-                             NULL\r
-                             };\r
-static char *one_per[] = { "identification",\r
-                           "bibliographic",\r
-                           "format",\r
-                           "title",\r
-                           "author",\r
-                           "headline",\r
-                           "firstpublished",\r
-                           "genre",\r
-                           "group",\r
-                           "description",\r
-                           "leafname",\r
-                           "height",\r
-                           "width",\r
-                           "forgiveness",\r
-                           "colophon",\r
-                           NULL\r
-                         };\r
-\r
-static char *required[] = {\r
-                "cover", "height",\r
-                "cover", "width",\r
-                "cover", "format",\r
-                "resources", "auxiliary",\r
-                "auxiliary", "leafname",\r
-                "auxiliary", "description",\r
-                "ifiction", "story",\r
-                "story", "identification",\r
-                "story", "bibliographic",\r
-                "identification", "ifid",\r
-                "identification", "format",\r
-                "bibliographic", "title",\r
-                "bibliographic", "author",\r
-                "colophon", "generator",\r
-                "colophon", "originated",\r
-                NULL, NULL\r
-                };\r
-static char *zarfian[] = {\r
-        "Merciful",\r
-        "Polite",\r
-        "Tough",\r
-        "Nasty",\r
-        "Cruel",\r
-        NULL\r
-        };\r
-\r
-struct ifiction_info {\r
-        int32 width;\r
-        int32 height;\r
-        int format;\r
-        };\r
-static void ifiction_validate_tag(struct XMLTag *xtg, struct ifiction_info *xti, IFErrorHandler err_h, void *ectx)\r
-{\r
- int i;\r
- char ebuf[512];\r
- struct XMLTag *parent=xtg->next;\r
- if (parent)\r
- {\r
- for(i=0;leaf_tags[i];i++)\r
-  if (strcmp(parent->tag,leaf_tags[i])==0)\r
-   {\r
-    sprintf(ebuf, "Error: (line %d) Tag <%s> is not permitted within tag <%s>",\r
-        xtg->beginl,xtg->tag,parent->tag);\r
-    err_h(ebuf,ectx);\r
-    }\r
- for(i=0;required[i];i+=2)\r
- if (strcmp(required[i],parent->tag)==0 && strcmp(required[i+1],xtg->tag)==0)\r
-  parent->rocurrences[i]=1;\r
- for(i=0;one_per[i];i++)\r
- if (strcmp(one_per[i],xtg->tag)==0)\r
-  if (parent->occurences[i]) { \r
-                               sprintf(ebuf,"Error: (line %d) Found more than one <%s> within <%s>",xtg->beginl,xtg->tag,\r
-                                        parent->tag);\r
-                               err_h(ebuf,ectx);\r
-                             }\r
-   else parent->occurences[i]=1;\r
- }\r
- for(i=0;required[i];i+=2)\r
- if (strcmp(required[i],xtg->tag)==0 && !xtg->rocurrences[i])\r
- {\r
-  sprintf(ebuf,"Error: (line %d) Tag <%s> is required within <%s>",xtg->beginl, required[i+1],xtg->tag);\r
-  err_h(ebuf,ectx);\r
- }\r
- if (parent && strcmp(parent->tag,"identification")==0)\r
- {\r
-  if (strcmp(xtg->tag,"format")==0)\r
-  {\r
-   int i;\r
-   for(i=0;format_registry[i];i++) if (memcmp(xtg->begin,format_registry[i],strlen(format_registry[i]))==0) break;\r
-   if (format_registry[i]) xti->format=i;\r
-   else\r
-   {\r
-    char bf[256];\r
-    memcpy(bf,xtg->begin,xtg->end-xtg->begin);\r
-    bf[xtg->end-xtg->begin]=0;\r
-    xti->format=-1;\r
-    sprintf(ebuf,"Warning: (line %d) Unknown format %s.",xtg->beginl,bf);\r
-    err_h(ebuf,ectx);\r
-   }\r
-  }\r
- }\r
- if (parent && strcmp(parent->tag,"cover")==0)\r
- {\r
- if (strcmp(xtg->tag,"width")==0)\r
- {\r
-  int i;\r
-  sscanf(xtg->begin,"%d",&i);\r
-  if (i<120)\r
-  {\r
-  sprintf(ebuf,"Warning: (line %d) Cover art width should not be less than 120.",xtg->beginl);\r
-  err_h(ebuf,ectx);\r
-  }\r
-  if (i>1200)\r
-  {\r
-  sprintf(ebuf,"Warning: (line %d) Cover art width should not exceed 1200.",xtg->beginl);\r
-  err_h(ebuf,ectx);\r
-  }\r
-  if (!xti->width) xti->width=i;\r
-  if (xti->height && (xti->width> 2 * xti->height || xti->height > 2 * xti->width))\r
-  {\r
-  sprintf(ebuf,"Warning: (line %d) Cover art aspect ratio exceeds 2:1.",xtg->beginl);\r
-  err_h(ebuf,ectx);\r
-  }\r
-\r
- }\r
- if (strcmp(xtg->tag,"height")==0)\r
- {\r
-  int i;\r
-  sscanf(xtg->begin,"%d",&i);\r
-  if (i<120)\r
-  {\r
-  sprintf(ebuf,"Warning: (line %d) Cover art height should not be less than 120.",xtg->beginl);\r
-  err_h(ebuf,ectx);\r
-  }\r
-  if (i>1200)\r
-  {\r
-  sprintf(ebuf,"Warning: (line %d) Cover art height should not exceed 1200.",xtg->beginl);\r
-  err_h(ebuf,ectx);\r
-  }\r
-  if (!xti->height) xti->height=i;\r
-  if (xti->width && (xti->width> 2 * xti->height || xti->height > 2 * xti->width))\r
-  {\r
-  sprintf(ebuf,"Warning: (line %d) Cover art aspect ratio exceeds 2:1.",xtg->beginl);\r
-  err_h(ebuf,ectx);\r
-  }\r
-\r
- }\r
- if (strcmp(xtg->tag,"format")==0 && memcmp(xtg->begin,"jpg",3) && memcmp(xtg->begin,"png",3))\r
- {\r
-  sprintf(ebuf,"Warning: (line %d) <format> should be one of: png, jpg.",xtg->beginl);\r
-  err_h(ebuf,ectx);\r
- }\r
- }\r
- if (parent && strcmp(parent->tag,"bibliographic")==0)\r
- {\r
-  char *p;\r
-  if (isspace(*xtg->begin)|| isspace(*(xtg->end-1)))\r
-   {\r
-    sprintf(ebuf,"Warning: (line %d) Extraneous spaces at beginning or end of tag <%s>.",xtg->beginl,xtg->tag);\r
-    err_h(ebuf,ectx);\r
-   }\r
-  for(p=xtg->begin;p<xtg->end-1;p++)\r
-/* Obsoleted by Revision 6\r
-  if (isspace(*p) && isspace(*(p+1)))\r
-  {\r
-  sprintf(ebuf,"Warning: (line %d) Extraneous spaces found in tag <%s>.",xtg->beginl, xtg->tag);\r
-  err_h(ebuf,ectx);\r
-  }\r
-  else if (isspace(*p) && *p!=' ')\r
-  {\r
-  sprintf(ebuf,"Warning: (line %d) Improper whitespace character found in tag <%s>.",xtg->beginl, xtg->tag);\r
-  err_h(ebuf,ectx);\r
-\r
-  }\r
-*/\r
- if (strcmp(xtg->tag, "description") && xtg->end-xtg->begin > 240)\r
- { \r
-  sprintf(ebuf,"Warning: (line %d) Tag <%s> length exceeds treaty guidelines",xtg->beginl, xtg->tag);\r
-  err_h(ebuf,ectx);\r
- }\r
- if (strcmp(xtg->tag, "description")==0 && xtg->end-xtg->begin > 2400)\r
- {\r
-  sprintf(ebuf,"Warning: (line %d) Tag <%s> length exceeds treaty guidelines",xtg->beginl, xtg->tag);\r
-  err_h(ebuf,ectx);\r
- }\r
- if (strcmp(xtg->tag,"firstpublished")==0)\r
- {\r
-  int l=xtg->end-xtg->begin;\r
-  if ((l!=4 && l!=10) ||\r
-      (!isdigit(xtg->begin[0]) ||\r
-       !isdigit(xtg->begin[1]) ||\r
-       !isdigit(xtg->begin[2]) ||\r
-       !isdigit(xtg->begin[3])) ||\r
-      (l==10 && ( xtg->begin[4]!='-' ||\r
-                  xtg->begin[7]!='-' ||\r
-                  !isdigit(xtg->begin[5]) ||\r
-                  !isdigit(xtg->begin[6]) ||\r
-                  !(xtg->begin[5]=='0' || xtg->begin[5]=='1') ||\r
-                  !(xtg->begin[5]=='0' || xtg->begin[6]<='2') ||\r
-                  !isdigit(xtg->begin[8]) ||\r
-                  !isdigit(xtg->begin[9]))))\r
-  {\r
-   sprintf(ebuf,"Warning: (line %d) Tag <%s> should be format YYYY or YYYY-MM-DD",xtg->beginl, xtg->tag);\r
-   err_h(ebuf,ectx);\r
-  }\r
- }\r
- if (strcmp(xtg->tag,"seriesnumber")==0)\r
- {\r
-  char *l;\r
-  if (*xtg->begin=='0' && xtg->end!=xtg->begin+1)\r
-  {\r
-   sprintf(ebuf,"Warning: (line %d) Tag <%s> should not use leading zeroes",xtg->beginl, xtg->tag);\r
-   err_h(ebuf,ectx);\r
-  }\r
-\r
-  for(l=xtg->begin;l<xtg->end;l++) if (!isdigit(*l))\r
-  {\r
-   sprintf(ebuf,"Warning: (line %d) Tag <%s> should be a positive number",xtg->beginl, xtg->tag);\r
-   err_h(ebuf,ectx);\r
-  }\r
- }\r
- if (strcmp(xtg->tag,"forgiveness")==0)\r
- {\r
-  int l;\r
-  for(l=0;zarfian[l];l++) if (memcmp(xtg->begin,zarfian[l],strlen(zarfian[l]))==0) break;\r
-  if (!zarfian[l])\r
-  {\r
-   sprintf(ebuf,"Warning: (line %d) <forgiveness> should be one of: Merciful, Polite, Tough, Cruel",xtg->beginl);\r
-   err_h(ebuf,ectx);\r
-  }\r
- }\r
- }\r
- if (xti->format>0)\r
- { \r
-  for(i=0;format_registry[i];i++) if (strcmp(xtg->tag,format_registry[i])==0) break;\r
-  if (format_registry[i] && xti->format !=i)\r
-  {\r
-  sprintf(ebuf,"Warning: (line %d) Found <%s> tag, but story is identified as %s.",xtg->beginl, xtg->tag, format_registry[xti->format]);\r
-  err_h(ebuf,ectx);\r
-  }\r
- }\r
- if (strcmp(xtg->tag,"story")==0)\r
- {\r
-  xti->format=-1;\r
-  xti->width=0;\r
-  xti->height=0;\r
- }\r
-\r
-}\r
-\r
-\r
-\r
-void ifiction_parse(char *md, IFCloseTag close_tag, void *close_ctx, IFErrorHandler error_handler, void *error_ctx)\r
-{\r
-char *xml, buffer[2400], *aep, *mda=md, ebuffer[512];\r
-struct XMLTag *parse=NULL, *xtg;\r
-struct ifiction_info xti;\r
-char BOM[3]={ 0xEF, 0xBB, 0xBF};\r
-xti.width=0;\r
-xti.height=0;\r
-xti.format=-1;\r
-llp=1;\r
-lnlst=md;\r
-\r
-while(*mda && isspace(*mda)) mda++;\r
-if (memcmp(mda,BOM,3)==0)\r
-{ mda+=3;\r
-  while(*mda && isspace(*mda)) mda++;\r
-}\r
-\r
-\r
-if (strncmp("<?xml version=\"1.0\" encoding=\"UTF-8\"?>",mda,\r
-        strlen("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"))\r
-    &&\r
-    strncmp("<?xml version=\"1.0\" encoding=\"utf-8\"?>",mda,\r
-        strlen("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"))\r
-   )\r
-{\r
- error_handler("Error: XML header not found.",error_ctx);\r
- return;\r
-}\r
-\r
-xml=strstr(md,"<ifindex");\r
-if (!xml) {\r
- error_handler("Error: <ifindex> not found",error_ctx);\r
- return;\r
- }\r
-while(xml && *xml)\r
-{\r
- char *bp, *ep, *tp;\r
- while(*xml&&*xml!='<') xml++;\r
- if (!*xml) break;\r
- bp=xml;\r
- tp=strchr(bp+1,'<');\r
- ep=strchr(bp+1,'>');\r
- if (!ep) break;\r
- if (tp && tp < ep)\r
-  { xml=tp; continue; }\r
- if (!tp) tp=ep+1; \r
- if (bp[1]=='/') /* end tag */\r
- {\r
-   strncpy(buffer,bp+2,(ep-bp)-2);\r
-   buffer[(ep-bp)-2]=0;\r
-   if (parse && strcmp(buffer,parse->tag)==0)\r
-   { /* copasetic. Close the tag */\r
-    xtg=parse;\r
-    parse=xtg->next;\r
-    xtg->end=ep-strlen(buffer)-2;\r
-    ifiction_validate_tag(xtg,&xti,error_handler, error_ctx);\r
-    close_tag(xtg,close_ctx);\r
-    free(xtg);\r
-   }\r
-   else\r
-   {\r
-    for(xtg=parse;xtg && strcmp(buffer,xtg->tag);xtg=xtg->next);\r
-    if (xtg) /* Intervening unclosed tags */\r
-    { for(xtg=parse;xtg && strcmp(buffer,parse->tag);xtg=parse)\r
-     {\r
-      xtg->end=xml-1;\r
-      parse=xtg->next;\r
-      sprintf(ebuffer,"Error: (line %d) unclosed <%s> tag",xtg->beginl,xtg->tag);\r
-      error_handler(ebuffer,error_ctx);\r
-      ifiction_validate_tag(xtg,&xti,error_handler, error_ctx);\r
-      close_tag(xtg,close_ctx);\r
-      free(xtg);\r
-     }\r
-     xtg=parse;\r
-     if (xtg)\r
-     {\r
-      xtg->end=xml-1;\r
-      parse=xtg->next;\r
-      ifiction_validate_tag(xtg,&xti, error_handler, error_ctx);\r
-      close_tag(xtg,close_ctx);\r
-      free(xtg);\r
-     }\r
-    }\r
-    else\r
-    { \r
-      sprintf(ebuffer,"Error: (line %d) saw </%s> without <%s>",getln(xml), buffer,buffer);\r
-      error_handler(ebuffer,error_ctx);\r
-    }\r
-   }\r
-\r
- }\r
- else if(*(ep-1)=='/' || bp[1]=='!') /* unterminated tag */\r
- {\r
-  /* Do nothing */\r
- }\r
- else /* Terminated tag beginning */\r
- {\r
-  int i;\r
-  xtg=(struct XMLTag *)my_malloc(sizeof(struct XMLTag),"XML Tag");\r
-  xtg->next=parse;\r
-  xtg->beginl=getln(bp);\r
-  for(i=0;bp[i+1]=='_' || bp[i+1]=='-' || isalnum(bp[i+1]);i++)\r
-   xtg->tag[i]=bp[i+1];\r
-  if (i==0)\r
-  { xml=tp;\r
-    free(xtg);\r
-    continue;\r
-  }\r
-  parse=xtg;\r
-  parse->tag[i]=0;\r
-  strncpy(parse->fulltag,bp+1,ep-bp-1);\r
-  parse->fulltag[ep-bp-1]=0;\r
-  parse->begin=ep+1;\r
- }\r
- xml=tp;\r
-}\r
- while (parse)\r
- {\r
-      xtg=parse;\r
-      xtg->end=aep-1;\r
-      parse=xtg->next;\r
-      sprintf(ebuffer,"Error: (line %d) Unclosed tag <%s>",xtg->beginl,xtg->tag);\r
-      ifiction_validate_tag(xtg,&xti,error_handler, error_ctx);\r
-      close_tag(xtg,close_ctx);\r
-      free(xtg);\r
- }\r
-}\r
-\r
-struct get_tag\r
-{\r
- char *tag;\r
- char *parent;\r
- char *output;\r
- char *target;\r
-};\r
-\r
-static void ifiction_null_eh(char *e, void *c)\r
-{\r
- if (e || c) { }\r
-\r
-}\r
-\r
-static void ifiction_find_value(struct XMLTag *xtg, void *xti)\r
-{\r
- struct get_tag *gt=(struct get_tag *)xti;\r
-\r
- if (gt->output && !gt->target) return;\r
- if (gt->target && gt->output && strcmp(gt->output,gt->target)==0) { gt->target=NULL; free(gt->output); gt->output=NULL; }\r
- if (((!xtg->next && !gt->parent) || (xtg->next && gt->parent && strcmp(xtg->next->tag,gt->parent)==0)) &&\r
-      strcmp(xtg->tag,gt->tag)==0)\r
- {\r
-  int32 l = xtg->end-xtg->begin;\r
-\r
-  if (gt->output) free(gt->output);\r
-  gt->output=(char *)my_malloc(l+1, "ifiction tag buffer");\r
-  memcpy(gt->output, xtg->begin, l);\r
-  gt->output[l]=0;\r
-\r
- }\r
-}\r
-\r
-\r
-char *ifiction_get_tag(char *md, char *p, char *t, char *from)\r
-{\r
- struct get_tag gt;\r
- gt.output=NULL;\r
- gt.parent=p;\r
- gt.tag=t;\r
- gt.target=from;\r
- ifiction_parse(md,ifiction_find_value,&gt,ifiction_null_eh,NULL);\r
- if (gt.target){ if (gt.output) free(gt.output); return NULL; }\r
- return gt.output;\r
-}\r