Journal Portage de TapTempo en C à la Unix-like

Posté par  (site Web personnel) . Licence CC By‑SA.
Étiquettes :
16
10
mar.
2018

Salut Nal,

Il manquait une version C à la tradition Unix, c'est maintenant fait !

Du coup, pour préserver l'esprit, options courtes uniquement et pas de version, mais pour le reste, c'est assez complet avec contrôle des bornes pour les paramètres. Il ne manque que la page de manuel, ce sera pour une autre fois :)

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>

#define NSAMPLES 5
#define MAX_NSAMPLES 20
#define RESET_TIME 5
#define PRECISION 0

extern  char *__progname;

static  void usage(void);

int
main(int argc, char *argv[])
{
        double           times[MAX_NSAMPLES];    
        int              curlen = 0;
        double           curtime;
        struct timeval   tp;
        int              ch;
        char            *p = NULL, *r = NULL, *s = NULL;
        int              precision = PRECISION, reset_time = RESET_TIME, nsamples = NSAMPLES;
        char             fmtstr[30];
        char            *line = NULL;
        size_t           linesize = 0;
        ssize_t          linelen;

        while ((ch = getopt(argc, argv, "p:r:s:")) != -1)
                switch (ch) {
                case 'p':
                        p = optarg;     
                        break;
                case 'r':
                        r = optarg;             
                        break;
                case 's':
                        s = optarg;             
                        break;
                default:
                        usage();
                }
        argc -= optind;
        if (argc > 0)
                warnx("too many arguments");
        if (p && sscanf(p, "%i", &precision) != 1)
                warnx("-p argument: not an integer");
        if (r && sscanf(r, "%i", &reset_time) != 1)
                warnx("-r argument: not an integer");
        if (s && sscanf(s, "%i", &nsamples) != 1)
                warnx("-r argument: not an integer");
        if (precision < 0 || precision > 6) {
                warnx("-p argument: should be an integer between 0 and 6");
                precision = PRECISION;
        }
        if (reset_time < 1) {
                warnx("-r argument: should be at least 1");
                reset_time = RESET_TIME;
        }
        if (nsamples < 2 || nsamples > MAX_NSAMPLES) {
                fprintf(stderr, "%s: -s argument: should be an integer between 2 and %d\n",
                    __progname, MAX_NSAMPLES);
                nsamples = NSAMPLES;
        }
        int ret = snprintf(fmtstr, sizeof(fmtstr), "Tempo: %%.%df bpm ", precision);
        if (ret == -1 || ret >= sizeof(fmtstr))
                errx(1, "snprintf");

        printf("Hit enter key for each beat (q to quit).");
        while ((fflush(stdout), linelen = getline(&line, &linesize, stdin)) != -1) {
                if (!strncmp(line, "q\n", linelen))
                        break;
                gettimeofday(&tp, NULL);
                curtime = tp.tv_sec + tp.tv_usec / 1e6;
                if (curlen > 0 && curtime - times[curlen-1] > reset_time)
                        curlen = 0;
                if (curlen == nsamples)
                        for (int i = 0; i < nsamples - 1; i++)
                                times[i] = times[i+1];
                else
                        curlen++;
                times[curlen-1] = curtime;
                if (curlen < 2) {
                        printf("[Hit enter key one more time to start bpm computation...]");
                        continue;
                }
                printf(fmtstr, 60 * (curlen-1) / (curtime - times[0]));
        }
        free(line);

        if (ferror(stdin))
                warn("getline");
        puts("Bye Bye!");

        return (0);
}

static void
usage(void)
{
        fprintf(stderr, "usage: %s [-p precision] [-r reset-time] [-s samples]\n", __progname);
        exit(1);
}

J'ai pas vraiment l'habitude du C, donc c'était l'occasion de s'amuser un peu et essayer d'écrire un programme C sans segfaults :)

  • # Forum

    Posté par  . Évalué à 9.

    Ça me rappelle un truc sur le forum…

    • [^] # Re: Forum

      Posté par  . Évalué à 3.

      Ce n'est que pur coïncidence ça devait arriver ;)

  • # Patch de portabilité

    Posté par  (site Web personnel) . Évalué à 4.

    --- taptempo.c.orig     2018-03-10 21:57:44.155831000 +0100
    +++ taptempo.c  2018-03-10 21:59:19.953300000 +0100
    @@ -1,4 +1,5 @@
     #include <err.h>
    +#define _WITH_GETLINE
     #include <stdio.h>
     #include <stdlib.h>
     #include <string.h>
    

    Avec un gettext pour traduire les chaînes, ça serait mieux, mais l’exercice est laissé au lecteur…

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.