Question

J'ai un démon qui lit un fichier de configuration afin de savoir où écrire quelque chose. Dans le fichier de configuration, une ligne comme celle-ci existe:

output = /tmp/foo/%d/%s/output

Ou, il peut ressembler à ceci:

output = /tmp/foo/%s/output/%d

... ou tout simplement comme ceci:

output = /tmp/foo/%s/output

... ou enfin:

output = /tmp/output

Je cette ligne comme CFG-> pathfmt dans mon programme. Ce que je suis en train de faire maintenant est de trouver une façon intelligente de l'utiliser.

Un peu plus d'explications, le chemin peut contenir jusqu'à deux composants à formater. % D sera étendu comme ID d'emploi (int),% s comme un nom de travail (chaîne). L'utilisateur peut utiliser l'une, deux ou aucun dans le fichier de configuration. Je dois savoir ce qu'ils veulent et dans quel ordre avant de passer finalement à snprintf (). Je sorte de le réduire, mais je continue de vouloir parler à strtok () et qui semble laid.

Je veux donner aux utilisateurs ce genre de flexibilité, mais je suis à me perdre à la recherche d'un moyen portable sensible, pour la mettre en œuvre. Je suis aussi une perte complète et totale pour savoir comment commencer à chercher pour cela.

Je serais très heureux si:

  • Quelqu'un pourrait me aider à réduire l'expression de recherche pour trouver de bons exemples
  • Quelqu'un pourrait poster un lien vers un certain projet OSS application de cette
  • Quelqu'un pourrait poster un code psuedo

Je ne veux pas le code écrit pour moi, je suis vraiment coincé sur ce que (je pense) devrait être quelque chose de très simple et besoin d'aide pour prendre la première bouchée. Je me sens vraiment que je suis sur la pensée et donnant sur l'évidence.

Le résultat final doit être une fonction booléenne comme ceci:

bool output_sugar(const char *fmt, int jobid, const char *jobname, struct job *j);

Il serait alors appeler snprintf () (sensiblement) sur j-> outpath, retour faux si une sorte de déchets (c.-à-% suivi par quelque chose de pas s, d ou%) est dans la ligne de configuration (ou son null). Les contrôles de santé d'esprit sont faciles, je suis juste avoir un peu de temps à le nombre (et l'ordre) des arguments pour mettre en forme correcte.

Merci d'avance. En outre, vous pouvez modifier ce titre si vous avez la réputation de le faire, comme je l'ai dit, je ne suis pas tout à fait sûr de savoir comment poser la question sur une seule ligne. Je pense que ce que je besoin est un , mais il se sent maladroit à l'aide d'une lexer épanouie / analyseur pour gérer une chaîne simple.

Était-ce utile?

La solution

Oui, vous avez besoin d'un analyseur de quelque sorte. Il ne doit pas être complexe, bien que:

void format_filename(const char *fmt, int jobid, const char *jobname,
                     char *buffer, size_t buflen)
{
    char *end = buffer + buflen - 1;
    const char *src = fmt;
    char *dst = buffer;
    char c;
    assert(buffer != 0 && fmt != 0 && buflen != 0 && jobname != 0);
    while ((c = *src++) != '\0')
    {
        if (dst >= end)
            err_exit("buffer overflow in %s(): format = %s\n",
                     __func__, fmt);
        else if (c != '%')
            *dst++ = c;
        else if ((c = *src++) == '\0' || c == '%')
        {
            *dst++ = '%';
            if (c == '\0')
                break;
        }
        else if (c == 's')
        {
            size_t len = strlen(jobname);
            if (len > end - dst)
                err_exit("buffer overflow on jobname in %s(): format = %s\n",
                         __func__, fmt);
            else
            {
                strcpy(dst, jobname);
                dst += len;
            }
        }
        else if (c == 'd')
        {
             int nchars = snprintf(dst, end - dst, "%d", jobid);
             if (nchars < 0 || nchars >= end - dst)
                 err_exit("format error on jobid in %s(); format = %s\n",
                          __func__, fmt);
             dst += nchars;
        }
        else
            err_exit("invalid format character %d in %s(): format = %s\n",
                     c, __func__, fmt);
    }
    *dst = '\0';
}

Code maintenant testé. Notez qu'il prend en charge la notation « %% » pour permettre à l'utilisateur d'intégrer un « % » dans la sortie. Il traite également un « % » à la fin de la chaîne comme valide et équivalent à « %% ». Il appelle Err_Exit () en cas d'erreur; vous pouvez choisir des stratégies alternatives d'erreur que votre système convient. Je suppose simplement que vous avez inclus <assert.h>, <stdio.h> et <string.h> et l'en-tête de la fonction err_exit() (de variadique).


Code d'essai ...

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>

static void err_exit(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    exit(1);
}

... format_filename() comme ci-dessus, puis ...

#define DIM(x) (sizeof(x)/sizeof(*(x)))

static const char *format[] =
{
    "/tmp/%d/name/%s",
    "/tmp/%s/number/%d",
    "/tmp/%s.%d%%",
    "/tmp/%",
};

int main(void)
{
    char buffer[64];
    size_t i;

    for (i = 0; i < DIM(format); i++)
    {
        format_filename(format[i], 1234, "job-name", buffer, sizeof(buffer));
        printf("fmt = %-20s; name = %s\n", format[i], buffer);
    }

    return(0);
}

Autres conseils

Utilisation strtok est une erreur sujette. Vous pouvez traiter vos variables comme un mini-langue à l'aide (fl) LEX et YACC. Il y a tutoriel ici

%{
#include <stdio.h>
%}

%%
%d                      printf("%04d",jobid);
%s                      printf("%s",stripspaces(dirname));
%%

J'ai fait une enveloppe ODBC qui vous permettent de faire des choses comme dbprintf ( "insérer dans les valeurs blah% s% D% T% Y", trucs ici ...); Mais il y a de nombreuses années et je bit et analysé la chaîne de format en utilisant strtok.

Si le nombre d'options est petit et que vous ne voulez pas autrement / besoin de la flexibilité supplémentaire et la complexité d'un analyseur, vous pouvez simplement rechercher pour chaque remplacement potentiel à l'aide strstr substring ().

Si vous avez seulement deux options, vous pouvez assez créer un à quatre branches si / structure autre (seulement A, que B, à la fois avec A avant B, à la fois avec B avant A) où appeler sprintf () avec les arguments commandés correctement. Dans le cas contraire, faites plusieurs appels sprintf (), dont chacun ne remplace que le premier marqueur de remplacement dans la chaîne de format. (Ce qui implique la construction d'une liste dont le remplacement sont nécessaires et les trier en apparence ordre ...)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top