Changeset ac9b4f2 in mainline for uspace/lib/sif/src/sif.c


Ignore:
Timestamp:
2024-08-20T23:43:53Z (2 months ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
Children:
f8cb1bc5
Parents:
bff8619
Message:

Change SIF storage format to be more XML-like

While slightly more difficult to parse than previously, this potentially
allows the use of standard XML utilities to more or less process SIF files.
Also, insert newline after every tag to be more readable / more
accessible to diff/patch.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/sif/src/sif.c

    rbff8619 rac9b4f2  
    4545#include <adt/list.h>
    4646#include <adt/odict.h>
     47#include <ctype.h>
    4748#include <errno.h>
     49#include <stdbool.h>
    4850#include <stdio.h>
    4951#include <stdlib.h>
     
    5355
    5456static errno_t sif_export_node(sif_node_t *, FILE *);
    55 static errno_t sif_import_node(sif_node_t *, FILE *, sif_node_t **);
     57static errno_t sif_import_node(sif_node_t *, FILE *, sif_node_t **, bool *);
    5658static sif_attr_t *sif_node_first_attr(sif_node_t *);
    5759static sif_attr_t *sif_node_next_attr(sif_attr_t *);
     
    6062static int sif_attr_cmp(void *, void *);
    6163
     64/** Determine if character can start a name.
     65 *
     66 * @param c Character
     67 * @return @c true iff the character can start a name
     68 */
     69static bool sif_is_name_start_char(char c)
     70{
     71        return isalpha(c) || c == '_';
     72}
     73
     74/** Determine if character can continue a name.
     75 *
     76 * @param c Character
     77 * @return @c true iff the character can continue a name
     78 */
     79static bool sif_is_name_char(char c)
     80{
     81        return isalnum(c) || c == '-' || c == '.';
     82}
     83
    6284/** Create new SIF node.
    6385 *
     
    205227        sif_node_t *root = NULL;
    206228        errno_t rc;
     229        bool endtag;
    207230        FILE *f;
    208231
     
    223246        }
    224247
    225         rc = sif_import_node(NULL, f, &root);
    226         if (rc != EOK)
     248        rc = sif_import_node(NULL, f, &root, &endtag);
     249        if (rc != EOK || endtag == true)
    227250                goto error;
    228251
     
    343366        if (rc != EOK)
    344367                goto error;
    345 
    346         if (fputc('\n', f) == EOF) {
    347                 rc = EIO;
    348                 goto error;
    349         }
    350368
    351369        if (fflush(f) == EOF) {
     
    563581}
    564582
    565 /** Export string to file.
    566  *
    567  * Export string to file (the string is bracketed and escaped).
     583/** Export node name to file.
     584 *
     585 * Export node name to file.
    568586 *
    569587 * @param str String
     
    571589 * @return EOK on success, EIO on I/O error
    572590 */
     591static errno_t sif_export_name(const char *str, FILE *f)
     592{
     593        if (fputs(str, f) == EOF)
     594                return EIO;
     595
     596        return EOK;
     597}
     598
     599/** Export string to file.
     600 *
     601 * Export string to file (the string is double-quoted and escaped).
     602 *
     603 * @param str String
     604 * @param f File
     605 * @return EOK on success, EIO on I/O error
     606 */
    573607static errno_t sif_export_string(const char *str, FILE *f)
    574608{
    575609        const char *cp;
    576610
    577         if (fputc('[', f) == EOF)
     611        if (fputc('"', f) == EOF)
    578612                return EIO;
    579613
    580614        cp = str;
    581615        while (*cp != '\0') {
    582                 if (*cp == ']' || *cp == '\\') {
    583                         if (fputc('\\', f) == EOF)
     616                if (*cp == '<') {
     617                        if (fputs("&lt;", f) == EOF)
     618                                return EIO;
     619                } else if (*cp == '"') {
     620                        if (fputs("&quot;", f) == EOF)
     621                                return EIO;
     622                } else {
     623                        if (fputc(*cp, f) == EOF)
    584624                                return EIO;
    585625                }
    586                 if (fputc(*cp, f) == EOF)
     626
     627                ++cp;
     628        }
     629
     630        if (fputc('"', f) == EOF)
     631                return EIO;
     632
     633        return EOK;
     634}
     635
     636/** Read characters from file, make sure they match the specified sequence.
     637 *
     638 * @param f File
     639 * @param chars Expected sequence of characters to be read
     640 *
     641 * @return EOK on success, EIO on I/O error or mismatch
     642 */
     643static errno_t sif_get_verify_chars(FILE *f, const char *chars)
     644{
     645        const char *cp;
     646        char c;
     647
     648        cp = chars;
     649        while (*cp != '\0') {
     650                c = fgetc(f);
     651                if (c != *cp)
    587652                        return EIO;
    588653                ++cp;
    589654        }
    590655
    591         if (fputc(']', f) == EOF)
    592                 return EIO;
    593 
    594         return EOK;
    595 }
    596 
    597 /** Import string from file.
    598  *
    599  * Import string from file (the string in the file must be
    600  * properly bracketed and escaped).
    601  *
     656        return EOK;
     657}
     658
     659/** Import name from file.
     660 * *
    602661 * @param f File
    603662 * @param rstr Place to store pointer to newly allocated string
    604663 * @return EOK on success, EIO on I/O error
    605664 */
    606 static errno_t sif_import_string(FILE *f, char **rstr)
     665static errno_t sif_import_name(FILE *f, char **rstr)
    607666{
    608667        char *str;
     
    620679
    621680        c = fgetc(f);
    622         if (c != '[') {
     681        if (!sif_is_name_start_char(c)) {
    623682                rc = EIO;
    624683                goto error;
     
    626685
    627686        while (true) {
    628                 c = fgetc(f);
    629                 if (c == EOF) {
    630                         rc = EIO;
    631                         goto error;
    632                 }
    633 
    634                 if (c == ']')
    635                         break;
    636 
    637                 if (c == '\\') {
    638                         c = fgetc(f);
    639                         if (c == EOF) {
    640                                 rc = EIO;
    641                                 goto error;
    642                         }
    643                 }
    644 
    645687                if (sidx >= str_size) {
    646688                        str_size *= 2;
     
    655697
    656698                str[sidx++] = c;
     699
     700                c = fgetc(f);
     701                if (!sif_is_name_char(c))
     702                        break;
     703        }
     704
     705        ungetc(c, f);
     706
     707        str[sidx] = '\0';
     708        *rstr = str;
     709        return EOK;
     710error:
     711        free(str);
     712        return rc;
     713}
     714
     715/** Import string from file.
     716 *
     717 * Import string from file (the string in the file must be
     718 * properly quoted and escaped).
     719 *
     720 * @param f File
     721 * @param rstr Place to store pointer to newly allocated string
     722 * @return EOK on success, EIO on I/O error
     723 */
     724static errno_t sif_import_string(FILE *f, char **rstr)
     725{
     726        char *str;
     727        char *nstr;
     728        size_t str_size;
     729        size_t sidx;
     730        int c;
     731        errno_t rc;
     732
     733        str_size = 1;
     734        sidx = 0;
     735        str = malloc(str_size + 1);
     736        if (str == NULL)
     737                return ENOMEM;
     738
     739        c = fgetc(f);
     740        if (c != '"') {
     741                rc = EIO;
     742                goto error;
     743        }
     744
     745        while (true) {
     746                c = fgetc(f);
     747                if (c == EOF) {
     748                        rc = EIO;
     749                        goto error;
     750                }
     751
     752                if (c == '"')
     753                        break;
     754
     755                if (c == '&') {
     756                        c = fgetc(f);
     757                        if (c == EOF) {
     758                                rc = EIO;
     759                                goto error;
     760                        }
     761
     762                        if (c == 'q') {
     763                                rc = sif_get_verify_chars(f, "uot;");
     764                                if (rc != EOK)
     765                                        goto error;
     766                        } else if (c == 'l') {
     767                                rc = sif_get_verify_chars(f, "t;");
     768                                if (rc != EOK)
     769                                        goto error;
     770                        } else {
     771                                rc = EIO;
     772                                goto error;
     773                        }
     774                }
     775
     776                if (sidx >= str_size) {
     777                        str_size *= 2;
     778                        nstr = realloc(str, str_size + 1);
     779                        if (nstr == NULL) {
     780                                rc = ENOMEM;
     781                                goto error;
     782                        }
     783
     784                        str = nstr;
     785                }
     786
     787                str[sidx++] = c;
    657788        }
    658789
     
    680811        int c;
    681812
    682         rc = sif_import_string(f, &aname);
     813        rc = sif_import_name(f, &aname);
    683814        if (rc != EOK)
    684815                goto error;
     
    723854        errno_t rc;
    724855
    725         rc = sif_export_string(attr->aname, f);
     856        rc = sif_export_name(attr->aname, f);
    726857        if (rc != EOK)
    727858                return rc;
     
    749880        sif_node_t *child;
    750881
    751         rc = sif_export_string(node->ntype, f);
     882        if (fputc('<', f) == EOF)
     883                return EIO;
     884
     885        rc = sif_export_name(node->ntype, f);
    752886        if (rc != EOK)
    753887                return rc;
     
    755889        /* Attributes */
    756890
    757         if (fputc('(', f) == EOF)
    758                 return EIO;
    759 
    760891        attr = sif_node_first_attr(node);
    761892        while (attr != NULL) {
     893                if (fputc(' ', f) == EOF)
     894                        return EIO;
     895
    762896                rc = sif_export_attr(attr, f);
    763897                if (rc != EOK)
     
    767901        }
    768902
    769         if (fputc(')', f) == EOF)
     903        if (fputs(">\n", f) == EOF)
    770904                return EIO;
    771905
    772906        /* Child nodes */
    773 
    774         if (fputc('{', f) == EOF)
    775                 return EIO;
    776907
    777908        child = sif_node_first_child(node);
     
    784915        }
    785916
    786         if (fputc('}', f) == EOF)
     917        if (fputs("</", f) == EOF)
     918                return EIO;
     919
     920        rc = sif_export_name(node->ntype, f);
     921        if (rc != EOK)
     922                return rc;
     923
     924        if (fputs(">\n", f) == EOF)
    787925                return EIO;
    788926
     
    795933 * @param f File
    796934 * @param rnode Place to store pointer to imported node
     935 * @param rendtag Place to store @c true iff end tag is encountered
    797936 * @return EOK on success, EIO on I/O error
    798937 */
    799 static errno_t sif_import_node(sif_node_t *parent, FILE *f, sif_node_t **rnode)
     938static errno_t sif_import_node(sif_node_t *parent, FILE *f, sif_node_t **rnode,
     939    bool *rendtag)
    800940{
    801941        errno_t rc;
     
    803943        sif_node_t *child;
    804944        sif_attr_t *attr = NULL;
     945        bool endtag;
     946        bool cendtag;
    805947        char *ntype;
    806948        int c;
     
    810952                return ENOMEM;
    811953
    812         rc = sif_import_string(f, &ntype);
     954        c = fgetc(f);
     955        while (isspace(c))
     956                c = fgetc(f);
     957
     958        if (c != '<') {
     959                rc = EIO;
     960                goto error;
     961        }
     962
     963        c = fgetc(f);
     964        if (c == '/') {
     965                endtag = true;
     966        } else {
     967                endtag = false;
     968                ungetc(c, f);
     969        }
     970
     971        rc = sif_import_name(f, &ntype);
    813972        if (rc != EOK)
    814973                goto error;
     
    817976
    818977        /* Attributes */
    819 
    820         c = fgetc(f);
    821         if (c != '(') {
    822                 rc = EIO;
    823                 goto error;
    824         }
    825978
    826979        c = fgetc(f);
     
    830983        }
    831984
    832         while (c != ')') {
     985        while (c != '>') {
     986                /* End tags cannot have attributes */
     987                if (endtag) {
     988                        rc = EIO;
     989                        goto error;
     990                }
     991
     992                while (isspace(c))
     993                        c = fgetc(f);
    833994                ungetc(c, f);
    834995
     
    8481009        /* Child nodes */
    8491010
    850         c = fgetc(f);
    851         if (c != '{') {
    852                 rc = EIO;
    853                 goto error;
    854         }
    855 
    856         c = fgetc(f);
    857         if (c == EOF) {
    858                 rc = EIO;
    859                 goto error;
    860         }
    861 
    862         while (c != '}') {
    863                 ungetc(c, f);
    864 
    865                 rc = sif_import_node(node, f, &child);
    866                 if (rc != EOK)
    867                         goto error;
    868 
    869                 list_append(&child->lparent, &node->children);
    870 
    871                 c = fgetc(f);
    872                 if (c == EOF) {
    873                         rc = EIO;
    874                         goto error;
     1011        if (!endtag) {
     1012                while (true) {
     1013                        rc = sif_import_node(node, f, &child, &cendtag);
     1014                        if (rc != EOK)
     1015                                goto error;
     1016
     1017                        if (cendtag) {
     1018                                sif_node_delete(child);
     1019                                break;
     1020                        }
     1021
     1022                        list_append(&child->lparent, &node->children);
    8751023                }
    8761024        }
    8771025
    8781026        *rnode = node;
     1027        *rendtag = endtag;
    8791028        return EOK;
    8801029error:
Note: See TracChangeset for help on using the changeset viewer.