Partage
  • Partager sur Facebook
  • Partager sur Twitter

zJustificator

Exercice du 25 Avril au 15 Mai

    26 avril 2010 à 7:22:21

    Bonjour,

    Je créé ce topic, pour que vous puissiez demander des conseils, des renseignements supplémentaires ou encore vos solutions pour le premier exercice du mois de Mai.

    Amusez-vous bien.
    • Partager sur Facebook
    • Partager sur Twitter
      26 avril 2010 à 21:14:17

      Salut à tous,

      Voici ma participation pour le mois de mai.

      L'idée générale du programme est la suivante. On récupère les mots un par un pour former des lignes, en mettant le plus possible de mots sur chaque ligne, mais sans dépasser la limite fixée par l'utilisateur.
      Ensuite, pour chaque ligne, il s'agit de trouver un certain nombre d'espaces entre les mots de façon à ce que le texte soit justifier. Je fais ça en 3 étapes : d'abord on fait une répartition homogène des espaces (on en met "nombre d'espaces à placer / nombre de places" partout). S'il reste des espaces à placer, on les met après les signes de ponctuation, toujours de façon homogène (parce que là c'est moins gênant que les mots soient espacés). Et puis s'il en reste encore, on les met comme on veut (ou peut).

      Je trouve ça un peu long, mais je sais pas faire plus court...

      justify.c
      #include <ctype.h>
      #include <stdbool.h>
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      
      #include "buffer.h"
      
      
      struct line_s {
          int     num_words;
          int     num_puncts; /* Number of words that end with a punctuation mark */
          int     sum_len_words;
          bool    is_last;
          char  **words;
      };
      
      
      /* Return a word read from `instream` and store its length in `len`.
       * The memory allocated by the function to store the word belongs to the
       * caller. That is, the next call of the function won't overwrite it.
       */
      char *read_word(FILE *instream, int *len)
      {
          int c, null = '\0';
          char *word;
          buffer_t *buffer = buffer_init(sizeof(char), 7);
      
          while (((c = getc(instream)) == ' ' || c == '\t' || c == '\r') 
                  && c != EOF);
      
          if (c == '\n' || c == EOF) {
              free(buffer_contents(buffer));
              free(buffer);
              return NULL;
          }
      
          if (c != EOF)
              buffer_append(buffer, &c);
      
          while (!isspace(c = getc(instream)) && c != EOF)
              buffer_append(buffer, &c);
      
          ungetc(c, instream);
      
          buffer_append(buffer, &null);
      
          *len = buffer_size(buffer) - 1;
          word = buffer_contents(buffer);
      
          free(buffer);
      
          return word;
      }
      
      bool ends_with_punct(char *word)
      {
          char c = word[strlen(word) - 1];
          return (c == ',' || c == '.' || c == ':' || c == '?' || 
                  c == '!' || c == ';');
      }
       
      /* Return the next line as a null-terminated array of words, each word being a
       * string.
       * The function allocates space for the line.
       * The line is read from `instream`, and the function packs as many words in
       * it as possible without exceding `num_cols`.
       */
      struct line_s get_line(FILE *instream, const int num_cols)
      {
          void *null = NULL;
          bool this_word_ends_with_punc;
          int line_len;
          static int next_word_len;
          static char *next_word = NULL;
          struct line_s line = {0, 0, 0, false, NULL};
      
          buffer_t *line_buffer = buffer_init(sizeof(char *), 20);
      
          line_len = -1;
      
          if (next_word == NULL)
              next_word = read_word(instream, &next_word_len);
      
          while (next_word != NULL) {
              line_len += next_word_len + 1; /* + 1 for the ' ' before the word. */
              /* If line_len > num_cols and there is nothing in the buffer, then the
               * word cannot fit on a single line. In that case, force it. */
              if (line_len > num_cols && buffer_size(line_buffer) != 0) {
                  break;
              }
      
              /* If we forced the word on the line. */
              if (line_len > num_cols)
                  fprintf(stderr, "Warning: overfull line because '%s' cannot"
                          " fit on a single line.\n", next_word);
      
              buffer_append(line_buffer, &next_word);
              ++line.num_words;
              this_word_ends_with_punc = ends_with_punct(next_word);
              line.sum_len_words += next_word_len;
      
              next_word = read_word(instream, &next_word_len);
      
              if (this_word_ends_with_punc
                      && next_word != NULL
                      && line_len + next_word_len + 1 <= num_cols)
                  ++line.num_puncts;
          }
      
          /* If no word could fit one the line, put one anyway. */
      
          buffer_append(line_buffer, &null);
      
          if (line_len != -1)
              line.words = buffer_contents(line_buffer);
          line.is_last = (next_word == NULL);
      
          free(line_buffer);
      
          return line;
      }
      
      void put_spaces(FILE *outstream, int num)
      {
          int i;
          for (i = 0; i < num; ++i)
              putc(' ', outstream);
      }
      
      /* Justify a single paragraph. */
      void justify_par(FILE *instream, FILE *outstream, const int num_cols)
      {
          int base_num_spaces, rest_num_spaces, spaces_per_punct, extra_spaces;
          char **word_p;
          struct line_s line, next_line;
      
          next_line = get_line(instream, num_cols);
      
          while ((line = next_line).words != NULL) {
      
              next_line = get_line(instream, num_cols);
      
              /* The normal number of spaces between 2 words. */
              base_num_spaces = line.num_words > 1
                  ? (num_cols - line.sum_len_words) / (line.num_words - 1) 
                  : 0;
              /* The number of extra spaces for this line. */
              rest_num_spaces = line.num_words > 1 
                  ? (num_cols - line.sum_len_words) % (line.num_words - 1) 
                  : 0;
              /* The extra spaces are put in priority after punctuation marks, and
               * then after the first words of the line (that last part is
               * arbitrary, there may be a way that looks better). */
              spaces_per_punct = line.num_puncts >= 1 
                  ? rest_num_spaces / line.num_puncts
                  : 0;
              if (spaces_per_punct > 3 * base_num_spaces - 1)
                  spaces_per_punct = 3 * base_num_spaces - 1;
      
              extra_spaces = line.num_puncts >= 1 
                  ? rest_num_spaces - line.num_puncts * spaces_per_punct
                  : rest_num_spaces;
      
      #ifdef DEBUG
              printf("%2d %2d %2d %2d %2d %2d %2d |",
                      line.sum_len_words, line.num_words, line.num_puncts,
                      base_num_spaces, rest_num_spaces, spaces_per_punct,
                      extra_spaces);
      #endif
      
              for (word_p = line.words; *word_p != NULL; ++word_p) {
                  fprintf(outstream, "%s", *word_p);
                  /* Do not put space after the last word. */
                  if (*(word_p + 1) != NULL) {
                      if (line.is_last) {
                          putc(' ', outstream);
                      } else {
                          put_spaces(outstream, base_num_spaces);
                          if (ends_with_punct(*word_p))
                              put_spaces(outstream, spaces_per_punct);
                          if (extra_spaces > 0) {
                              putc(' ', outstream);
                              --extra_spaces;
                          }
                      }
                  }
                  free(*word_p);
              }
              putc('\n', outstream);
              free(line.words);
          }
      }
      
      void justify_text(FILE *instream, FILE *outstream, const int num_cols)
      {
          for (;;) {
              justify_par(instream, outstream, num_cols);
              if (feof(instream))
                  break;
              putc('\n', outstream);
          }
      }
      
      void print_usage(FILE *stream)
      {
          fprintf(stream, "usage: justify -c numcols [-i infile] [-o outfile] \n");
      }
      
      void print_help(void)
      {
          print_usage(stdout);
          printf("                                                            \n");
          printf("This program justifies a text to make it fit exactly into a \n");
          printf("given number of columns.                                    \n");
          printf("                                                            \n");
          printf("Options:                                                    \n");
          printf("    -c      specify the number of columns                   \n");
          printf("    -i      specify a file from which to read (defaults to  \n");
          printf("            the standard input)                             \n");
          printf("    -o      specify a file on which to write (defaults to   \n");
          printf("            the standard output)                            \n");
          printf("    -h      print this message                              \n");
      }
      
      int main (int argc, char **argv)
      {
          char *in_name = NULL, *out_name = NULL;
          int i, num_cols = 0;
          FILE *instream = stdin;
          FILE *outstream = stdout;
      
          for (i = 1; i < argc; ++i) {
              if (argv[i][0] == '-') {
                  if (strcmp(argv[i] + 1, "c") == 0) {
                      ++i;
                      if (i >= argc) {
                          print_usage(stderr);
                          exit(1);
                      }
                      if (sscanf(argv[i], "%d", &num_cols) != 1 || num_cols <= 0) {
                          fprintf(stderr, "Error: option -c requires a positive"
                                  " integer as argument.\n");
                          exit(1);
                      }
                  } else if (strcmp(argv[i] + 1, "i") == 0) {
                      ++i;
                      if (i >= argc) {
                          print_usage(stderr);
                          exit(1);
                      }
                      in_name = argv[i];
                  } else if (strcmp(argv[i] + 1, "o") == 0) {
                      ++i;
                      if (i >= argc) {
                          print_usage(stderr);
                          exit(1);
                      }
                      out_name = argv[i];
                  } else if (strcmp(argv[i] + 1, "h") == 0 
                          || strcmp(argv[i] + 1, "help") == 0) {
                      print_help();
                      exit(0);
                  } else {
                      fprintf(stderr, "Error: unknown option '%s'.\n", argv[i]);
                      fprintf(stderr, "Type `justify -help` for more information.\n");
                      exit(1);
                  }
              } else {
                  print_usage(stderr);
                  fprintf(stderr, "Type `justify -help` for more information.\n");
                  exit(1);
              }
          }
      
          if (num_cols == 0) {
              print_usage(stderr);
              fprintf(stderr, "Type `justify -help` for more information.\n");
              exit(1);
          }
      
          if (in_name != NULL)
              if ((instream = fopen(in_name, "r")) == NULL) {
                  fprintf(stderr, "Error while opening file '%s': ", in_name);
                  perror(NULL);
                  exit(1);
              }
      
          if (out_name != NULL)
              if ((outstream = fopen(out_name, "w")) == NULL) {
                  fprintf(stderr, "Error while opening file '%s': ", out_name);
                  perror(NULL);
                  exit(1);
              }
          
          justify_text(instream, outstream, num_cols);
      
          fclose(outstream);
          fclose(instream);
      
          return 0;
      }
      


      Et puis une structure de donnée pour accumuler des objets dans un tableau sans se préoccuper des allocations de mémoire.

      buffer.h
      #ifndef H__BUFFER
      #define H__BUFFER
      
      typedef struct buffer_s buffer_t;
      
      buffer_t   *buffer_init(const size_t elem_size, const size_t initial_size);
      void        buffer_append(buffer_t *, const void *);
      void        buffer_flush(buffer_t *);
      size_t      buffer_size(const buffer_t *);
      void       *buffer_contents(const buffer_t *);
      
      #endif
      


      buffer.c
      #include <stdlib.h>
      #include <stdio.h>
      #include <string.h>
      
      #include "buffer.h"
      
      struct buffer_s
      {
          size_t  elem_size;
          size_t  physical_size;
          size_t  logical_size;
          void    *contents;
      };
       
      void *xmalloc(size_t size)
      {
          void *p;
          if ((p = malloc(size)) == NULL) {
              fprintf(stderr, "Error: cannot allocate more memory.\n");
              exit(1);
          }
          return p;
      }
      
      void *xrealloc(void *dest, size_t size)
      {
          void *p;
          if ((p = realloc(dest, size)) == NULL) {
              fprintf(stderr, "Error: cannot allocate more memory.\n");
              exit(1);
          }
          return p;
      }          
      
      struct buffer_s *buffer_init(const size_t elem_size, const size_t initial_size)
      {
          struct buffer_s *buffer = malloc(sizeof(*buffer));
      
          buffer->elem_size = elem_size;
          buffer->physical_size = initial_size;
          buffer->logical_size = 0;
          buffer->contents = xmalloc(elem_size * initial_size);
      
          return buffer;
      }
      
      void buffer_append(struct buffer_s *buffer, const void *elem)
      {
          if (buffer->logical_size == buffer->physical_size) {
              buffer->physical_size *= 2;
              buffer->contents = xrealloc(buffer->contents, buffer->physical_size);
          }
      
          memcpy((char*)buffer->contents + buffer->logical_size * buffer->elem_size,
                  elem,
                  buffer->elem_size);
          ++buffer->logical_size;
      }                                        
      
      void buffer_flush(struct buffer_s *buffer)
      {
          buffer->logical_size = 0;
      }
      
      size_t buffer_size(const struct buffer_s *buffer)
      {
          return buffer->logical_size;
      }
      
      void *buffer_contents(const struct buffer_s *buffer)
      {
          return buffer->contents;
      }
      


      Un exemple :
      $ ./justify -c 50 -i mit-license 
      Copyright (c) <year> <copyright holders>
      
      Permission is hereby granted,  free of charge,  to
      any  person  obtaining a copy of this software and
      associated  documentation  files (the "Software"),
      to  deal  in  the  Software  without  restriction,
      including  without  limitation  the rights to use,
      copy,    modify,   merge,   publish,   distribute,
      sublicense,    and/or sell copies of the Software,
      and  to  permit  persons  to  whom the Software is
      furnished  to  do  so,    subject to the following
      conditions:
      
      The  above  copyright  notice  and this permission
      notice   shall   be  included  in  all  copies  or
      substantial portions of the Software.
      
      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY
      OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
      LIMITED  TO  THE  WARRANTIES  OF  MERCHANTABILITY,
      FITNESS    FOR    A    PARTICULAR    PURPOSE   AND
      NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR
      COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
      OR  OTHER  LIABILITY,  WHETHER  IN  AN  ACTION  OF
      CONTRACT,  TORT OR OTHERWISE, ARISING FROM, OUT OF
      OR  IN  CONNECTION WITH THE SOFTWARE OR THE USE OR
      OTHER DEALINGS IN THE SOFTWARE.
      • Partager sur Facebook
      • Partager sur Twitter
        5 mai 2010 à 1:08:21

        Je n'ai pas le temps de tout lire, mais je vois que tu te casses trop la tête avec les options passés en paramètre.
        Je te suggère de t'initier à <getopt.h>, ça simplifie énormément la vie.
        • Partager sur Facebook
        • Partager sur Twitter
          5 mai 2010 à 1:47:35

          Ouaip, j'y ai déjà jeté un coup d'oeil.

          M'enfin là, pour un exo, je me suis dit autant tout prendre à zéro. Bon, ça va parce qu'il n'y a pas 57 options différentes, là c'est clair que j'aurais fait autrement.

          Enfin en tous cas c'est sympa de passer, je commençais à me sentir seul sur ce topic :-°
          • Partager sur Facebook
          • Partager sur Twitter
            5 mai 2010 à 1:53:30

            En fait quand j'ai vu ça :
            for (i = 1; i < argc; ++i) {
                    if (argv[i][0] == '-') {
                        if (strcmp(argv[i] + 1, "c") == 0) {
                            ++i;
                            if (i >= argc) {
                                print_usage(stderr);
                                exit(1);
                            }
                            if (sscanf(argv[i], "%d", &num_cols) != 1 || num_cols <= 0) {
                                fprintf(stderr, "Error: option -c requires a positive"
                                        " integer as argument.\n");
                                exit(1);
                            }
                        } else if (strcmp(argv[i] + 1, "i") == 0) {
                            ++i;
                            if (i >= argc) {
                                print_usage(stderr);
                                exit(1);
                            }
                            in_name = argv[i];
                        } else if (strcmp(argv[i] + 1, "o") == 0) {
                            ++i;
                            if (i >= argc) {
                                print_usage(stderr);
                                exit(1);
                            }
                            out_name = argv[i];
                        } else if (strcmp(argv[i] + 1, "h") == 0 
                                || strcmp(argv[i] + 1, "help") == 0) {
                            print_help();
                            exit(0);
                        } else {
                            fprintf(stderr, "Error: unknown option '%s'.\n", argv[i]);
                            fprintf(stderr, "Type `justify -help` for more information.\n");
                            exit(1);
                        }
                    } else {
                        print_usage(stderr);
                        fprintf(stderr, "Type `justify -help` for more information.\n");
                        exit(1);
                    }
                }
            
                if (num_cols == 0) {
                    print_usage(stderr);
                    fprintf(stderr, "Type `justify -help` for more information.\n");
                    exit(1);
                }
            
                if (in_name != NULL)
                    if ((instream = fopen(in_name, "r")) == NULL) {
                        fprintf(stderr, "Error while opening file '%s': ", in_name);
                        perror(NULL);
                        exit(1);
                    }
            
                if (out_name != NULL)
                    if ((outstream = fopen(out_name, "w")) == NULL) {
                        fprintf(stderr, "Error while opening file '%s': ", out_name);
                        perror(NULL);
                        exit(1);
                    }
            

            J'ai eu de la peine pour toi !!
            Je me suis dit le pauvre, il a tout refait :)
            • Partager sur Facebook
            • Partager sur Twitter
              6 mai 2010 à 7:04:38

              Bonjour,

              histoire de tenir compagnie à Bad_Wolf, voici ma participation.

              Je n'ai pas pour habitude de poster plusieurs fichiers mais là j'ai un monstre. :-°

              L'algorithme utilisé ressemble à la description que fait Bas_Wolf du sien.
              A voir...

              Je me sers d'une structure LIFO, pour stocker les mots jusqu'à atteindre la longueur désirée.

              Cet exo aura été l'occasion d'essayer getopt pour la première fois.

              main.c
              #include "zjustificator.h"
              
              #include <unistd.h>
              #include <stdio.h>
              #include <stdlib.h>
              #include <string.h>
              
              struct param
              {
                  char *cArg;
                  char *iArg;
                  char *oArg;
                  int errflg;
              };
              
              
              
              void redir(char const *filename, char const *mode, FILE *stream)
              {
                  if(filename != NULL)
                  {
                      FILE *fp = freopen(filename, mode, stream);
                      if(fp == NULL)
                      {
                          perror("");
                          exit(EXIT_FAILURE);
                      }
                  }
              }
              
              
              void usage ( void )
              {
                  fprintf ( stderr,
                            "Usage : \n"
                            "zjustificator -c nombre_de_colonnes"
                            "[-i fichier_en_entree][-o fichier_en_sortie]" );
              }
              
              
              void parseArgs ( int argc, char *argv[], struct param *prm)
              {
                  int c;
                  extern char *optarg;
                  extern int optind, optopt;
              
                  opterr = 0;
                  while ( ( c = getopt ( argc, argv, ":c:i:o:" ) ) != EOF )
                  {
                      switch ( c )
                      {
                          case 'c':
                              prm->cArg =  optarg;
                              break;
                          case 'i':
                              prm->iArg = optarg;
                              break;
                          case 'o':
                              prm->oArg = optarg;
                              break;
                          case ':':
                              fprintf ( stderr,
                                        "Option -%c demande un parametre\n", optopt );
                              prm->errflg++;
                              break;
                          case '?':
                              fprintf ( stderr,
                                        "Option -%c inconnue\n", optopt );
                              prm->errflg++;
                          default:
                              break;
                      }
                  }
              }
              
              int main ( int argc, char *argv[] )
              {
                  struct param prm;
              
                  memset(&prm, 0, sizeof (struct param));
                  parseArgs(argc, argv, &prm);
              
                  if(prm.errflg)
                      usage();
                  else
                  {
                      char *endptr;
                      int nCol = strtol(prm.cArg, &endptr, 10);
                      if(*endptr != '\0')
                      {
                          fprintf(stderr,
                              "Impossible de convertir %s en long\n", prm.cArg);
                      }
                      else
                      {
                          redir(prm.iArg, "r", stdin);
                          redir(prm.oArg, "w", stdout);
                      }
                      zJustificator(nCol);
                  }
              
              
                  return EXIT_SUCCESS;
              }
              

              queue.h
              #ifndef H_QUEUE
              #define H_QUEUE
              
              typedef struct queue Queue;
              
              Queue *Queue_init ( void );
              int Queue_size ( Queue *p_queue );
              int Queue_isEmpty ( Queue *p_queue );
              void Queue_push ( Queue *p_queue, char *data );
              void Queue_pop ( Queue *p_queue );
              char *Queue_top ( Queue *p_queue );
              
              /* H_QUEUE */
              #endif
              


              queue.c
              #include "queue.h"
              #include <stdlib.h>
              
              typedef struct node
              {
                  char *data;
                  struct node *p_nxt;
              }Node;
              
              struct queue
              {
                  Node *input;
                  Node *output;
                  int size;
              };
              
              Queue *Queue_init ( void )
              {
                  Queue *p_new = malloc ( sizeof * p_new );
                  if ( p_new != NULL )
                  {
                      p_new->input = NULL;
                      p_new->output = NULL;
                      p_new->size = 0;
                  }
                  return p_new;
              }
              
              int Queue_size ( Queue *p_queue )
              {
                  return p_queue->size;
              }
              
              int Queue_isEmpty ( Queue *p_queue )
              {
                  return !Queue_size ( p_queue );
              }
              
              void Queue_push ( Queue *p_queue, char *data )
              {
                  Node *p_new = malloc ( sizeof * p_new );
                  if ( p_new != NULL )
                  {
                      p_new->data = data;
                      p_new->p_nxt = NULL;
              
                      if ( Queue_isEmpty ( p_queue ) )
                          p_queue->output = p_new;
                      else
                          p_queue->input->p_nxt = p_new;
              
                      p_queue->input = p_new;
                      p_queue->size++;
                  }
              }
              
              
              
              void Queue_pop ( Queue *p_queue )
              {
                  if ( !Queue_isEmpty ( p_queue ) )
                  {
                      Node *p_tmp = p_queue->output->p_nxt;
                      free ( p_queue->output ), p_queue->output = NULL;
                      p_queue->output = p_tmp;
                      p_queue->size--;
                  }
              }
              
              char *Queue_top ( Queue *p_queue )
              {
                  return p_queue->output->data;
              }
              

              zjustificator.h
              #ifndef H_JUSTIFICATOR
              #define H_JUSTIFICATOR
              
              /* Imprime dans stdout, le contenu de stdin justifié sur n colonnes */
              void zJustificator ( int n );
              
              /* H_JUSTIFICATOR */
              #endif
              

              zjustificator.c
              #include "zjustificator.h"
              #include "queue.h"
              
              #include <stdio.h>
              #include <stdlib.h>
              #include <ctype.h>
              #include <string.h>
              
              
              
              static int nChar(FILE *fp)
              {
                  int count = 0;
                  int c;
                  while((c = fgetc(fp)) != EOF)
                      count++;
              
                  rewind(fp);
              
                  return count;
              }
              
              
              static char *streamToStr(FILE *fp)
              {
                  int c;
                  char *buf = calloc((nChar(fp) + 1),  sizeof *buf);
                  char *pbuf = buf;
                  if(buf == NULL)
                  {
                      perror("Dans fonction streamToBuf");
                      exit(EXIT_FAILURE);
                  }
              
                  while((c = fgetc(fp)) != EOF)
                  {
                      *pbuf = c;
                      pbuf++;
                  }
                  return buf;
              }
              
              
              static char *my_strndup ( char const *s, int n )
              {
                  char *ret = calloc ( n + 1, sizeof * ret );
                  if ( ret != NULL )
                      strncpy ( ret, s, n );
              
                  return ret;
              }
              
              
              static void displaySpaces ( int q, int *r )
              {
                  int i;
                  for ( i = 0; i < q; i++ )
                      putchar ( ' ' );
                  if ( *r )
                  {
                      putchar ( ' ' );
                      ( *r )--;
                  }
              }
              
              
              static void displayLine ( Queue *p_queue, int q, int r )
              {
                  while ( !Queue_isEmpty ( p_queue ) )
                  {
                      char *p = Queue_top ( p_queue );
                      printf ( "%s", p );
                      Queue_pop ( p_queue );
                      free ( p ), p = NULL;
                      displaySpaces ( q, &r );
                  }
              }
              
              
              static char *skipSpaces ( char const *s )
              {
                  while ( *s != '\0' && isspace ( *s ) )
                      s++;
                  return ( char * ) s;
              }
              
              
              static char *getWord ( char const *s )
              {
                  while ( *s != '\0' && !isspace ( *s ) )
                      s++;
                  return ( char * ) s;
              }
              
              
              
              static void justify ( char const *s, int n )
              {
                  Queue *words = Queue_init();
                  int tailleLigne = 0;
                  char const *endWord = NULL;
              
                  while ( *s != '\0' )
                  {
                      s = skipSpaces ( s );
                      endWord = getWord ( s );
              
                      if ( endWord != s )
                      {
                          int lenWord = endWord - s;
                          if ( tailleLigne + lenWord + 1 >= n + 1)
                          {
                              int nInter =  Queue_size ( words ) - 1;
                              if(nInter)
                              {
                                  div_t d = div ( n + 1 - tailleLigne + nInter, nInter );
                                  displayLine ( words, d.quot, d.rem );
                              }
                              else
                                  displayLine ( words, 0, 0 );
              
                              tailleLigne = 0;
                              puts ( "" );
                          }
                          Queue_push ( words, my_strndup ( s, lenWord ) );
                          tailleLigne += lenWord + 1;
                          s = endWord;
                      }
                  }
              
                  while ( !Queue_isEmpty ( words ) )
                      displayLine ( words, 1, 0 );
              
                  free ( words ), words = NULL;
              }
              
              void zJustificator(int n)
              {
                  char *str = streamToStr(stdin);
                  justify(str, n);
              
                  free(str), str = NULL;
              }
              



              Exemple de sortie avec une justification de 20 colonnes. edit : Ne pas utiliser de caractères accentués. :-°
              Last    In,   First   
              Out,        souvent        
              abrégé          par          
              l'acronyme    LIFO,    
              signifie    dernier    
              arrivé,     premier     
              sorti    .    Cette    
              expression      est      
              utilisée         en         
              informatique   pour   
              décrire   une  mani  
              re  de  traiter des 
              données.  La  derni  
              re  donnée  ajoutée  
              la   structure  est  
              ainsi  la  premi re 
              être   retirée.  La  
              structure  de  pile  
              repose    sur    ce    
              principe.       Une       
              illustration
              courante    de   ce   
              traitement  est  la  
              pile    d'assiettes    
              sales  :  la  derni  
              re   posée  sur  le  
              dessus  de  la pile 
              est   la  premi  re  
              lavée.        Cette        
              expression      est      
              également    tr   s   
              utilisée         en         
              comptabilité
              analytique       et       
              d'une    mani    re    
              générale  dans  les  
              techniques       de       
              gestion         des         
              stocks.   Elle  est  
              dans     ce     cas     
              souvent    traduite    
              par    DEPS    pour    
              Dernier      entré,      
              premier sorti .


              Si il y a des courageux pour regarder, je commenterais. :D

              edit: correction d'une erreur dans zjustificator.c
              redit: C'est bon pour zjustificator.h... :-°
              • Partager sur Facebook
              • Partager sur Twitter
              Zeste de Savoir, le site qui en a dans le citron !
                6 mai 2010 à 8:28:11

                Citation : GurneyH




                Exemple de sortie avec une justification de 20 colonnes.

                Last    In,   First   
                Out,        souvent        






                Curieux, on peut en mettre plus sur la première ligne et dans les 20 colonnes :
                Last In, First Out,
                souvent
                • Partager sur Facebook
                • Partager sur Twitter
                  6 mai 2010 à 11:07:35

                  Citation : GurneyH


                  Exemple de sortie avec une justification de 20 colonnes.

                  Last    In,   First   
                  Out,        souvent        
                  abrégé          par          
                  l'acronyme    LIFO,    
                  signifie    dernier    
                  arrivé,     premier     
                  sorti    .    Cette    
                  expression      est      
                  utilisée         en         
                  informatique   pour   
                  décrire   une  mani  
                  re  de  traiter des 
                  données.  La  derni  
                  re  donnée  ajoutée  
                  la   structure  est  
                  ainsi  la  premi re 
                  être   retirée.  La  
                  structure  de  pile  
                  repose    sur    ce    
                  principe.       Une       
                  illustration
                  courante    de   ce   
                  traitement  est  la  
                  pile    d'assiettes    
                  sales  :  la  derni  
                  re   posée  sur  le  
                  dessus  de  la pile 
                  est   la  premi  re  
                  lavée.        Cette        
                  expression      est      
                  également    tr   s   
                  utilisée         en         
                  comptabilité
                  analytique       et       
                  d'une    mani    re    
                  générale  dans  les  
                  techniques       de       
                  gestion         des         
                  stocks.   Elle  est  
                  dans     ce     cas     
                  souvent    traduite    
                  par    DEPS    pour    
                  Dernier      entré,      
                  premier sorti .




                  Salut,

                  Je n'ai pas vu le code, mais il me semble que ton prog bouffe des caractères par ci par la, c'est pas trop régulier tout ca :)
                  A moins que ce ne soit un bête problème d'accents...

                  Par ailleurs, ton prog coupe parfois les mots en deux pour finir la ligne, et parfois non. C'est peut-être lié au problème ci-dessus.

                  Last In, First
                  Out, souvent
                  abrégé par
                  l'acronyme LIFO,
                  signifie dernier
                  arrivé, premier
                  sorti . Cette
                  expression est
                  utilisée en
                  informatique pour
                  décrire une maniè
                  re de traiter des
                  données. La derniè
                  re donnée ajoutée à
                  la structure est
                  ainsi la première
                  être retirée. La
                  structure de pile
                  repose sur ce
                  principe. Une
                  illustration
                  courante de ce
                  traitement est la
                  pile d'assiettes
                  sales : la derniè
                  re posée sur le
                  dessus de la pile
                  est la première
                  lavée. Cette
                  expression est
                  également trés
                  utilisée en
                  comptabilité
                  analytique et
                  d'une manière
                  générale dans les
                  techniques de
                  gestion des
                  stocks. Elle est
                  dans ce cas
                  souvent traduite
                  par DEPS pour
                  Dernier entré,
                  premier sorti .
                  • Partager sur Facebook
                  • Partager sur Twitter
                    6 mai 2010 à 11:53:29

                    Je confirme que chez moi aussi, les accents donnent une sortie pas du tout justifiée, ce qui est assez logique sachant qu'on ne compte pas vraiment le nombre de caractères mais le nombre d'octets.

                    C'est pour ça que dans mon exemple j'ai pris un texte en anglais :-° .
                    • Partager sur Facebook
                    • Partager sur Twitter
                      6 mai 2010 à 11:57:02

                      Citation : GurneyH


                      Exemple de sortie avec une justification de 20 colonnes.

                      Last    In,   First   
                      Out,        souvent        
                      abrégé          par          
                      l'acronyme    LIFO,    
                      signifie    dernier    
                      arrivé,     premier     
                      sorti    .    Cette    

                      Typographiquement, mettre des espaces entre le mot final et le point ne me paraît pas bon.
                      Au fait, pourquoi devant le point et pas devant la virgule?

                      @Bad_Wolf: Pour les lettres accentuées du français, il existe des encodages (notamment iso-8859-15) où chaque caractère est représenté par 1 octet, et inversement.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        6 mai 2010 à 15:16:58

                        Heu oui, désolé, j'ai pris le premier texte sous la main, pour l'exemple, et je n'ai pas fait attention au résultat... :-°
                        Avec les accents c'est n'importe quoi.

                        @candide: je pense avoir corrigé le problème que tu as signalé. Code édité.

                        @Marc Mongenet: non, ce n'est pas bon, mais le texte d'exemple, devait comporter un espace entre le mot et les points, à partir de là, c'est mort...

                        Avec un texte anglais, correctement typo, toujours justifié sur 20 colonnes.
                        Demomaking
                        originated      when      
                        crackers  wanted  to  
                        leave   their  marks  
                        on   programs   they   
                        had  cracked. At the 
                        beginning,      this      
                        mark  usually  was a 
                        simple   screen   of   
                        ASCII  graphics, but 
                        they   very  quickly  
                        evolved         into         
                        impressive  effects.  
                        Obviously    rivalry    
                        between    different    
                        groups     appeared,     
                        and     competitions     
                        started    to   take   
                        place.
                        
                        • Partager sur Facebook
                        • Partager sur Twitter
                        Zeste de Savoir, le site qui en a dans le citron !
                          7 mai 2010 à 17:55:20

                          Bonjour à tous,

                          Ça fait plaisir de voir que certaines personnes s'intéressent à l'exercice du mois (ça fait du bien de voir que l'on ne fait pas).
                          Je tiens à féliciter Bad_Wolf qui a proposé une solution opérationnelle en un temps très correct.
                          Je remercie aussi GurneyH, d'avoir participer (comme ça Bad_Wolf se sentira moins seul :p ).

                          J'en viens maintenant à la manière de justifier le texte, étant donné que l'on a tous les trois un algorithme assez similaire, je pense qu'il n'y a pas 36 solutions possibles.

                          @GurneyH : c'est normal que zjustificator.h et queue.c soient identiques ? ;)
                          • Partager sur Facebook
                          • Partager sur Twitter
                            7 mai 2010 à 17:59:28

                            Je cherchais le sujet partout, mais tu l'avais remonté. :p

                            Citation : lithrein


                            @GurneyH : c'est normal que zjustificator.h et queue.c soient identiques ?



                            Non... J'édites, en fait je cherchais, car me je me suis rendu compte que j'avais des headers en trop dans main.c et justificator.c.

                            Désolé, pour l'erreur. :-°
                            • Partager sur Facebook
                            • Partager sur Twitter
                            Zeste de Savoir, le site qui en a dans le citron !
                              8 mai 2010 à 20:16:17

                              Mon petit code (enfin quand même 150 lignes) de justification. J'ai eu la flemme de faire le traitement complet de la ligne de commande. Comme d'habitude, c'est un code conçu pour être utilisé dans un pipeline (jamais plus d'une ligne à justifier en RAM). 30 secondes pour justifier 1 Go de lorem ipsum
                              time ./lorem 1073741824 |./zJustificator 80  >/dev/null 
                              
                              real        0m28.225s
                              user        0m28.112s
                              sys        0m0.703s


                              zJustificator.c :
                              #include <ctype.h>
                              #include <stdio.h>
                              #include <stdlib.h>
                              #include <string.h>
                              
                              
                              struct justification_buffer {
                              	int columns;    /* number of columns for justification */
                              	char *line;     /* line of columns + 1 characters */
                              	int n_chars;    /* number of characters in line */
                              	int n_blanks;   /* number of blanks in line */
                              	int last_blank; /* last blank in line */
                              };
                              
                              
                              /*
                               * Fill the line with words, each word separated by 1 space (' ').
                               * One more character than buf->columns is filled, except on EOF.
                               * The filled line never starts with a space.
                               */
                              static void fill_buffer(struct justification_buffer *buf, FILE *input)
                              {
                              	while (buf->n_chars <= buf->columns) {
                              		const int c = getc(input);
                              
                              		if (c == EOF) return;
                              
                              		if (isspace(c)) {
                              			if (buf->n_chars != buf->last_blank) {
                              				buf->line[buf->n_chars] = ' ';
                              				buf->last_blank = buf->n_chars;
                              				++buf->n_blanks;
                              				++buf->n_chars;
                              			}
                              		}
                              		else {
                              			buf->line[buf->n_chars] = c;
                              			++buf->n_chars;
                              		}
                              	}
                              }
                              
                              
                              /*
                               * Output line as is, ignoring any final space.
                               */
                              static void output_as_is(const struct justification_buffer *buf, FILE *output)
                              {
                              	if (buf->n_chars > 0) {
                              		int i;
                              
                              		for (i = 0; i < buf->n_chars - 1; ++i)
                              			putc(buf->line[i], output);
                              		if (buf->line[i] != ' ')
                              			putc(buf->line[i], output);
                              	}
                              }
                              
                              
                              /*
                               * Copy input to output until EOF or a space is found.
                               * Output '\n' instead of final space.
                               */
                              static void flush_word(FILE *input, FILE *output)
                              {
                              	int c;
                              
                              	while ((c = getc(input)) != EOF) {
                              		if (isspace(c)) {
                              			putc('\n', output);
                              			return;
                              		}
                              		putc(c, output);
                              	}
                              }
                              
                              
                              /*
                               * Output words before buf->last_blank. Output is justified to
                               * buf->columns columns. Additonal spaces are evenly distributed,
                               * with more spaces at the beginning if it is impossible to be
                               * exactly even. The line is finished with a '\n'.
                               */
                              static void output_justified(const struct justification_buffer *buf, FILE *output)
                              {
                              	const int missing_blanks = buf->columns - buf->last_blank;
                              	int additional_blanks = 0;
                              	int remaining_additional_blanks = 0;
                              	int i;
                              
                              	if (buf->n_blanks > 1) {
                              		additional_blanks = missing_blanks / (buf->n_blanks - 1);
                              		remaining_additional_blanks = missing_blanks % (buf->n_blanks - 1);
                              	}
                              	
                              	for (i = 0; i < buf->last_blank; ++i) {
                              		putc(buf->line[i], output);
                              
                              		if (buf->line[i] == ' ') {
                              			int blanks_to_output = additional_blanks;
                              			if (remaining_additional_blanks > 0) {
                              				--remaining_additional_blanks;
                              				++blanks_to_output;
                              			}
                              			while (blanks_to_output-- > 0) {
                              				putc(' ', output);
                              			}
                              		}
                              	}
                              	putc('\n', output);
                              }
                              
                              
                              /*
                               * Move (un-output) characters after last blank to start of line.
                               */
                              static void reset_buffer(struct justification_buffer *buf)
                              {
                              	if (buf->last_blank > 0) {
                              		const int remaining = buf->n_chars - buf->last_blank - 1;
                              		memmove(buf->line, &buf->line[buf->last_blank + 1], remaining);
                              		buf->n_chars = remaining;
                              		buf->n_blanks = 0;
                              		buf->last_blank = 0;
                              	}
                              	else {
                              		buf->n_chars = 0;
                              	}
                              }
                              
                              
                              static void main_loop(struct justification_buffer *buf, FILE *input, FILE *output)
                              {
                              	for (;;) {
                              		fill_buffer(buf, input);
                              		if (buf->n_chars < buf->columns + 1) {
                              			output_as_is(buf, output);
                              			fputc('\n', output);
                              			return;
                              		}
                              		if (buf->n_blanks == 0) {
                              			output_as_is(buf, output);
                              			flush_word(input, output);
                              		}
                              		else {
                              			output_justified(buf, output);
                              		}
                              		reset_buffer(buf);
                              	}
                              }
                              
                              
                              static void zJustificator(int columns, FILE *input, FILE *output)
                              {
                              	struct justification_buffer buf = { 0 };
                              	
                              	buf.columns = columns;
                              	buf.line = malloc(columns + 1);
                              	if (!buf.line) exit(EXIT_FAILURE);
                              	main_loop(&buf, input, output);
                              	free(buf.line);
                              }
                              
                              
                              int main(int argc, char **argv)
                              {
                              	const int columns = argc > 1 ? atoi(argv[1]) : 20;
                              	
                              	zJustificator(columns, stdin, stdout);
                              
                              	return EXIT_SUCCESS;
                              }
                              

                              • Partager sur Facebook
                              • Partager sur Twitter
                                8 mai 2010 à 22:38:42

                                @marc mongenet:
                                question stupide probablement, comment génères tu un texte de 1Go ici? Il me semble qu'il y a une limitation...

                                Aussi, je viens de voir que mon programme plantait lamentablement si on ne spécifiait pas l'option -c. :'(

                                edit:
                                A la limite un lien vers le texte génèré, qu'on puisse faire des tests sur les mêmes fichiers. ;)
                                • Partager sur Facebook
                                • Partager sur Twitter
                                Zeste de Savoir, le site qui en a dans le citron !
                                  8 mai 2010 à 23:07:24

                                  Citation : GurneyH

                                  @marc mongenet:
                                  question stupide probablement, comment génères tu un texte de 1Go ici?



                                  Je ne peux pas répondre à sa place mais un lorem c'est un texte aléatoire de test. Donc je suppose que tu génères x fois pour atteindre la taille souhaitée alatoirement un Lorem Ipsum de 4437 octets.
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    8 mai 2010 à 23:13:19

                                    Heu, moi je n'arrive pas à générer plus de 71680 octets. o_O
                                    4437 octets, ok, mais 1 Go :-°

                                    Citation : candide


                                    Donc je suppose que tu génères x fois


                                    Tu veux dire qu'ensuite, on copie-colle? Une belle corvée pour faire des tests...
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    Zeste de Savoir, le site qui en a dans le citron !
                                      9 mai 2010 à 0:09:00

                                      Citation : GurneyH


                                      Citation : candide


                                      Donc je suppose que tu génères x fois


                                      Tu veux dire qu'ensuite, on copie-colle? Une belle corvée pour faire des tests...




                                      Tu programmes le copier-coller dans ton code de test. Euh d'ailleurs, ça ferait un très bon zExo ;)
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        9 mai 2010 à 1:10:57

                                        Hum, j'ai testé avec des gros fichiers, effectivement ce n'est pas une bonne idée de stocker tout le contenu du fichier en mémoire(ce que je fais.). :-°

                                        Surtout que pour faire ça, je parcours une première fois le fichier pour connaitre le nombre de caractères! Pas terrible terrible...

                                        J'ai testé le code de marc, ça n'a aucun rapport. Rien qu'avec un fichier de quelques Mo, la différence est sensible!
                                        J'imagine, que le code de bad wolf se comporte bien également(il traite à la volée).
                                        Il faudra que je teste.

                                        C'est dommage qu'on ai pas été plus nombreux. ;)
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        Zeste de Savoir, le site qui en a dans le citron !
                                          9 mai 2010 à 10:40:30

                                          Citation : GurneyH


                                          J'imagine, que le code de bad wolf se comporte bien également(il traite à la volée).


                                          Ben en fait, non. Je croyais aussi, mais apparemment j'ai une fuite de mémoire quelque part :( .
                                          Et je ne parle même pas des performances en temps : 22 secondes pour un fichier de 200 Mo. Ça ne vaut clairement pas le code de Marc :-° .
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            9 mai 2010 à 12:23:56

                                            J'étais curieux de voir ou je me situais au niveau des performances :
                                            Avec un fichier de 1,5 Go, généré avec ce code :
                                            #include <stdio.h>
                                            
                                            int
                                            main(int argc, char * argv[]) {
                                            
                                                int val;
                                                char const * const lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam fringilla congue lacus id vulputate. Sed eleifend ultricies mollis. Aliquam erat volutpat. Proin tincidunt dignissim risus sit amet bibendum. Nulla facilisi. Nunc et felis dolor. Praesent mattis pellentesque vehicula. Cras consequat sapien quis turpis imperdiet quis dignissim est egestas. Nunc venenatis pretium neque id venenatis. In id orci nec neque cursus viverra sit amet eu metus. Integer id enim non metus dictum laoreet ac non lorem.\n\nNulla facilisi. Sed facilisis viverra volutpat. In dignissim, lectus vitae venenatis varius, ligula nibh vulputate eros, ac varius est tellus non urna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In hac habitasse platea dictumst. Donec placerat aliquet commodo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean tincidunt pretium lacus, in aliquam massa facilisis et. Praesent gravida, sem sit amet cursus rutrum, ligula orci elementum enim, vel ultricies risus elit sit amet risus. Ut pulvinar porta venenatis. Donec lectus odio, pellentesque eget imperdiet convallis, dictum a dolor. Vestibulum eget felis mi. Maecenas congue mollis suscipit.\n\nVestibulum bibendum, lacus nec lobortis suscipit, nisl libero venenatis leo, at aliquet justo dui rutrum enim. Mauris in justo nibh. Pellentesque condimentum ligula a dolor porttitor facilisis. Aliquam erat volutpat. Ut elit urna, rutrum nec consequat eget, euismod ac augue. Duis tristique, sapien at fringilla egestas, diam massa lobortis magna, sit amet aliquet odio tortor at nisi. Nulla turpis dui, eleifend a faucibus id, luctus ut erat. Sed a ante lacus, eu varius tellus. Aenean varius pulvinar est, at congue risus dapibus pellentesque. Sed sit amet dui felis, nec egestas nulla. Donec consectetur consectetur lacus ac rhoncus. Nunc ac velit vitae velit dictum porttitor vitae et urna. Vivamus at orci ut justo fringilla ultricies. Ut ac turpis orci, et tincidunt massa. Nunc pharetra convallis ornare. Mauris urna leo, suscipit sed viverra ac, tincidunt non lorem.\n\nFusce accumsan mi ac metus pellentesque dictum. Suspendisse lectus diam, bibendum dictum cursus nec, adipiscing vitae elit. Donec ullamcorper nulla eu velit commodo a cursus sapien faucibus. Morbi condimentum turpis vel nulla sodales non pulvinar nulla suscipit. Donec feugiat pharetra porta. Nullam hendrerit quam id urna venenatis imperdiet. Nullam at enim vitae magna volutpat hendrerit. Proin accumsan libero vestibulum odio tincidunt ullamcorper hendrerit ligula ultrices. Suspendisse placerat consectetur elit, et molestie odio elementum a. Pellentesque varius mauris sed odio volutpat fringilla. Aliquam sit amet turpis enim, ac tempor nunc. Sed feugiat, neque eu ornare eleifend, libero mauris venenatis nisi, a fringilla ligula diam ac augue. Sed sollicitudin nunc ut augue facilisis commodo. Nulla tincidunt pretium bibendum. Donec elementum sem eget massa mattis et sollicitudin turpis faucibus. Mauris a ullamcorper elit. Sed vel hendrerit enim. Nam pellentesque dapibus accumsan. Mauris eget pharetra magna.\n\nSed eu tortor sit amet est mattis dignissim. Maecenas a nunc est. Sed lacinia massa turpis. Sed molestie tempor tincidunt. Praesent blandit, urna a dignissim adipiscing, justo dolor sodales mauris, vitae congue libero urna at velit. Pellentesque ut sapien metus, ac hendrerit sapien. Nullam non velit sapien, ac posuere eros. Etiam mollis dolor dictum enim posuere luctus. Donec volutpat, diam ac consectetur congue, eros urna mattis lacus, in viverra turpis libero sed nibh. Donec non magna ac elit suscipit sodales eget a neque. Integer lobortis rutrum justo a convallis. Quisque tincidunt cursus turpis, rutrum consequat diam interdum quis. Nunc tincidunt convallis justo. Maecenas vestibulum blandit sem, ac dictum urna scelerisque ac. Aliquam at justo a quam consectetur blandit eu et est. Fusce rutrum arcu id sem faucibus nec rutrum arcu suscipit. Etiam pretium sapien varius mi vulputate luctus sed ac dui. Sed eu orci ipsum.";
                                                
                                                sscanf(argv[argc-1], "%d", &val);
                                                while (val--)
                                                    printf("%s", lorem);
                                                
                                                return 0;
                                            }
                                            


                                            J'obtiens :

                                            Citation : Perfs


                                            time ./zJustify -c 50 -i input.txt -o output.txt

                                            real 12m15.691s
                                            user 0m16.256s
                                            sys 9m10.554s

                                            Taille du fichier d'entrée : 1 618 800 640 octets
                                            Taille du fichier de sortie: 1 727 201 280 octets

                                            time ./marc -c 50 < input.txt > output.txt

                                            real 8m56.844s
                                            user 0m35.778s
                                            sys 5m21.696s

                                            Taille du fichier d'entrée : 1 618 800 640 octets
                                            Taille du fichier de sortie: 1 617 203 200 octets



                                            Je me fais battre de 4 minutes :-° .
                                            Je dois encore pouvoir m'améliorer.

                                            Mon code :

                                            #include <stdio.h>
                                            #include <stdlib.h>
                                            #include <ctype.h>
                                            #include <string.h>
                                            
                                            #include "queue.h"
                                            
                                            #define MOT_LEN 100
                                            
                                            typedef struct opt_s {
                                                FILE * istream, * ostream;
                                                int nb_col;
                                                int h_active, err;
                                                char * i_path, * o_path;
                                            } opt_t;
                                            
                                            typedef struct word_s {
                                                size_t len;
                                                int is_end, punct;
                                                char word[MOT_LEN];
                                            } word_t;
                                            
                                            typedef struct line_s {
                                                queue_t * words;
                                                size_t len, nb_words, nb_punct;
                                                int last;
                                            } line_t;
                                            
                                            void
                                            usage (void) {
                                                puts("justify : Justifie le texte passe en entree.                                   ");
                                                puts("justify -c nb_col [-i istream] [-o ostream]                                  \n");
                                                puts("Options :                                                                      ");
                                                puts("-c  Nombre de colonnes.                                                        ");
                                                puts("-i  fichier en entree avec le texte a justifier (par defaut l'entree standard).");
                                                puts("-o  fichier ou sera ecrit le texte justifie (par defaut la sortie standard).   ");
                                                puts("-h  Affiche ce message d'aide.                                                 ");
                                            }
                                            
                                            int
                                            get_options (int ac, char * av[], opt_t * opt) {
                                                size_t i;
                                            
                                                if (ac < 2)
                                                    return 0;
                                                
                                                for (i = 1 ; i < ac ; ++i) {
                                                    if (av[i][0] == '-') {
                                                        if (av[i][1] == 'h' || !strcmp(av[i]+1, "-help")) {
                                                            opt->h_active = 1;
                                                        } else if (av[i][1] == 'c' || !strcmp(av[i]+1, "-columns")) {
                                                            ++i;
                                                            if (i >= ac) {
                                                                return 0;
                                                            }
                                                            if (sscanf(av[i], "%d", &opt->nb_col) != 1 || opt->nb_col < 1) {
                                                                puts("L'option 'c' attend un nombre entier naturel strictement positif.");
                                                                return 0;
                                                            }
                                                        } else if (av[i][1] == 'i' || !strcmp(av[i]+1, "-istream")) {
                                                            ++i;
                                                            if (i >= ac) {
                                                                return 0;
                                                            }
                                                            opt->i_path = av[i];
                                                        } else if (av[i][1] == 'o' || !strcmp(av[i]+1, "-ostream")) {
                                                            ++i;
                                                            if (i >= ac) {
                                                                return 0;
                                                            }
                                                            opt->o_path = av[i];
                                                        } else {
                                                            opt->err = 1;
                                                        }
                                                    }
                                                }
                                                return 1;
                                            }
                                            
                                            void
                                            print_spaces (size_t nb_spaces) {
                                                while (nb_spaces--)
                                                    putchar(' ');
                                            }
                                            
                                            unsigned int
                                            is_space (int c) {
                                                return c == ' '  || c == '\t' || c == '\f' || c == '\r' || c == '\v';
                                            }
                                            
                                            word_t *
                                            read_word (void) {
                                                word_t * w = NULL;
                                                int word_readed = 0;
                                                
                                                if ((w = calloc(sizeof *w, 1)) == NULL) {
                                                    perror("zJustificator");
                                                    return NULL;
                                                }
                                                
                                                while (word_readed == 0) {
                                                    int c;
                                                    
                                                    while ((c = getchar()) != EOF && !is_space(c)) {
                                                            word_readed = 1;
                                                            w->word[w->len++] = c;
                                                            if (c == '\n') {
                                                                w->is_end = 1;
                                                                break;
                                                            }
                                                    }
                                                    
                                                    if (c == EOF && word_readed) {
                                                        w->is_end = 1;
                                                    } else if (c == EOF && !word_readed) {
                                                        free(w), w = NULL;
                                                        return NULL;
                                                    }
                                                }
                                                
                                                if (ispunct(w->word[w->len-1])) {
                                                    w->punct = 1;
                                                }
                                                
                                                return w;
                                            }
                                            
                                            line_t *
                                            get_line (size_t nb_cols) {
                                                static word_t * exceed = NULL;
                                                line_t * line = NULL;
                                                word_t * current_word = NULL;
                                                
                                                if ((line = calloc(sizeof *line, 1)) == NULL) {
                                                   perror("zJustificator");
                                                   return NULL;
                                                }
                                                if ((line->words = init_queue()) == NULL) {
                                                    free(line), line = NULL;
                                                    perror("zJustificator");
                                                    return NULL;
                                                }
                                                
                                                while (line->len < nb_cols && !line->last) {
                                                    if (exceed == NULL) {
                                                        if ((current_word = read_word()) == NULL) {
                                                            break;
                                                        }
                                                    } else {
                                                        current_word = exceed;
                                                        exceed = NULL;
                                                    }
                                                    if (line->len+current_word->len+line->nb_words <= nb_cols) {
                                                        queue_push(current_word, line->words);
                                                        line->len += current_word->len;
                                                        line->nb_words++;
                                                        if (current_word->is_end) {
                                                            line->last = 1;
                                                            break;
                                                        }
                                                    } else {
                                                        exceed = current_word;
                                                        break;
                                                    }
                                                }
                                                
                                                if (line->nb_words) {
                                                    return line;
                                                } else {
                                                    free_queue(line->words), line->words = NULL;
                                                    free(line), line = NULL;
                                                    return NULL;
                                                }
                                            }
                                            
                                            void
                                            display_line (size_t nb_cols, line_t * line, int align) {
                                                int nb_spaces, nb_spaces_punct, nb_spaces_extra;
                                                word_t * w = NULL;
                                                size_t i;
                                                
                                                if (align) {
                                                    nb_spaces = line->nb_words > 1 ?
                                                        (nb_cols-line->len)/(line->nb_words-1)
                                                        :0;
                                                    nb_spaces_punct = line->nb_punct ?
                                                        (nb_cols-nb_spaces*(line->nb_words-1))/line->nb_punct
                                                        :0;
                                                    nb_spaces_extra = nb_cols
                                                      - line->len
                                                      - nb_spaces*(line->nb_words-1)
                                                      - nb_spaces_punct*line->nb_punct;
                                                }
                                                
                                                for (i = 0 ; i < line->nb_words ; ++i) {
                                                       
                                                       queue_pop(line->words, (void **)&w);
                                                       printf("%s", w->word);
                                                       
                                                        if(i < line->nb_words-1) {
                                                            if (align) {
                                                                print_spaces(nb_spaces);
                                                                if (nb_spaces_extra) {
                                                                    if (i < line->nb_words-2) {
                                                                        putchar(' ');
                                                                        --nb_spaces_extra;
                                                                    } else {
                                                                        print_spaces(nb_spaces_extra);
                                                                        nb_spaces_extra = 0;
                                                                    }
                                                                }
                                                                if (w->punct) {
                                                                    print_spaces(nb_spaces_punct);
                                                                }
                                                            } else {
                                                                putchar(' ');
                                                            }
                                                       }
                                                       free(w), w = NULL;
                                                }
                                            }
                                            
                                            int
                                            justify_line (size_t nb_cols) {
                                                line_t * current_line = NULL;
                                                size_t i;
                                                
                                                if ((current_line = get_line(nb_cols)) == NULL) {
                                                    return 0;
                                                }
                                            
                                                if (!current_line->last) {
                                                    display_line(nb_cols, current_line, 1);
                                                    putchar('\n');
                                                } else {
                                                    display_line(nb_cols, current_line, 0);
                                                }
                                            
                                                free_queue(current_line->words);
                                                free(current_line);
                                            
                                                return 1;
                                            }
                                            
                                            void
                                            zJustificator (int nb_col) {
                                                while (justify_line(nb_col));
                                            }
                                            
                                            FILE *
                                            redirect_stream(const char * path, const char * mode, FILE * stream) {
                                                FILE * _stream = NULL;
                                            
                                                if (path != NULL) {
                                                    if ((_stream = freopen(path, mode, stream)) == NULL) {
                                                        perror(path);
                                                    }
                                                }
                                            
                                                return path == NULL ? stream : _stream;
                                            }
                                            
                                            int
                                            main (int argc, char * argv[]) {
                                                opt_t opt = {NULL, NULL, 0, 0, 0, NULL, NULL};
                                            	
                                                if (!get_options(argc, argv, &opt) || opt.nb_col <= 0 || opt.err || opt.h_active) {
                                                    usage();
                                                    return opt.h_active ? EXIT_SUCCESS : EXIT_FAILURE;
                                                }
                                                
                                                if ((redirect_stream(opt.i_path, "r", stdin)) == NULL) {
                                                    return EXIT_FAILURE;
                                                }
                                                if ((redirect_stream(opt.o_path, "w", stdout)) == NULL) {
                                                    return EXIT_FAILURE;
                                                }
                                                
                                                zJustificator(opt.nb_col);
                                            
                                                return EXIT_SUCCESS;
                                            }
                                            

                                            #ifndef INCLUDED_PILE_H
                                            #define INCLUDED_PILE_H
                                            
                                            #include <stdlib.h>
                                            
                                            typedef struct elem_s {
                                                struct elem_s *next;
                                                void * value;
                                            } elem_t;
                                            
                                            typedef struct queue_s {
                                                struct elem_s * hd;
                                                struct elem_s * tl;
                                                size_t len;
                                            } queue_t;
                                            
                                            queue_t * init_queue (void);
                                            int queue_is_empty (queue_t * p);
                                            int queue_push (void * info, queue_t * p);
                                            int queue_pop (queue_t * p, void ** elem);
                                            int free_queue (queue_t * p);
                                            
                                            #endif
                                            

                                            #include <stdio.h>
                                            #include <stdlib.h>
                                            #include "queue.h"
                                            
                                            queue_t *
                                            init_queue (void) {
                                                queue_t * queue = calloc(sizeof *queue, 1);
                                            
                                                if (NULL == queue) {
                                                    return NULL;
                                                }
                                            
                                                queue->hd = NULL;
                                                queue->tl = NULL;
                                                queue->len = 0;
                                            
                                                return queue;
                                            }
                                            
                                            int
                                            queue_is_empty (queue_t * p) {
                                                return p->hd == NULL;
                                            }
                                            
                                            int
                                            queue_push (void * info, queue_t * p) {
                                                elem_t * elem = calloc(sizeof *elem, 1);
                                                if(NULL == elem) {
                                                    return 0;
                                                }
                                            
                                                elem->value = info;
                                                elem->next = NULL;
                                                
                                                if (queue_is_empty(p)) {
                                                    p->hd = elem;
                                                } else {
                                                    p->tl->next = elem;
                                                }
                                                p->tl = elem;
                                                p->len++;
                                            
                                                return 1;
                                            }
                                            
                                            int
                                            queue_pop (queue_t * p, void ** elem) {
                                                elem_t * cel = NULL;
                                                if (NULL == p->hd) {
                                                    return 0;
                                                }
                                            
                                                cel = p->hd->next;
                                                *elem = p->hd->value;
                                                free(p->hd);
                                                p->hd = cel;
                                                p->len--;
                                                
                                               return 1;
                                            }
                                            
                                            int
                                            free_queue (queue_t * p) {
                                                if (p == NULL) {
                                                    return 0;
                                                }
                                                
                                                if (NULL != p->hd) {
                                                    while (NULL != p->hd) {
                                                        elem_t * current = p->hd;
                                                        p->hd = p->hd->next;
                                                        free(current), current = NULL;
                                                    }
                                                }
                                                
                                                free(p), p = NULL;
                                                return 1;
                                            }
                                            


                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              9 mai 2010 à 14:03:58

                                              @Lithrein:
                                              Un lien, vers le fichier de test, stp... Pour tourner en minutes il doit être énorme.
                                              @Bad_wolf: Il y a bien une fuite de mémoire, mais je suis bien incapable de dire où.

                                              Il me semble que je n'ai pas de memory leak pour ma part, mais bonjour la consommation... :'(
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                              Zeste de Savoir, le site qui en a dans le citron !
                                                9 mai 2010 à 14:14:06

                                                @GurneyH : Le fichier fait 1,5 Go et je l'ai généré avec le code dans le premier secret avec 40000 itérations il me semble.
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  9 mai 2010 à 14:19:54

                                                  merci, désolé j'avais zappé ce secret. ;)
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                  Zeste de Savoir, le site qui en a dans le citron !
                                                    9 mai 2010 à 14:22:38

                                                    Citation : GurneyH

                                                    @marc mongenet:
                                                    question stupide probablement, comment génères tu un texte de 1Go


                                                    En fait, comme Lithrein ci-dessus, j'ai créé un petit exécutable qui sort lorem ipsum sur stdout, ce que je peux ensuite piper dans zJustificator:

                                                    lorem.c :
                                                    #include <stdio.h>
                                                    #include <stdlib.h>
                                                    
                                                    static const char lorem_ipsum[] =
                                                    	"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
                                                    	"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim "
                                                    	"ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut "
                                                    	"aliquip ex ea commodo consequat. Duis aute irure dolor in "
                                                    	"reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla "
                                                    	"pariatur. Excepteur sint occaecat cupidatat non proident, sunt in "
                                                    	"culpa qui officia deserunt mollit anim id est laborum.";
                                                    
                                                    static void usage(const char *argv0)
                                                    {
                                                    	fprintf(stderr, "Usage: %s number\n", argv0);
                                                    }
                                                    
                                                    
                                                    int main(int argc, char **argv)
                                                    {
                                                    	if (argc < 2) {
                                                    		puts(lorem_ipsum);
                                                    	}
                                                    	else if (argc == 2) {
                                                    		char *end;
                                                    		const long long n = strtoll(argv[1], &end, 0);
                                                    		long long i;
                                                    
                                                    		if (n < 0 || argv[1][0] == '\0' || *end != '\0') {
                                                    			usage(argv[0]);
                                                    			return EXIT_FAILURE;
                                                    		}
                                                    
                                                    		for (i = 0; i < n / sizeof lorem_ipsum; ++i) {
                                                    			puts(lorem_ipsum);
                                                    		}
                                                    		if (n % sizeof lorem_ipsum > 0) {
                                                    			for (i = 0; i < n % sizeof lorem_ipsum - 1; ++i)
                                                    				putchar(lorem_ipsum[i]);
                                                    			putchar('\n');
                                                    		}
                                                    	}
                                                    	else {
                                                    		usage(argv[0]);
                                                    		return EXIT_FAILURE;
                                                    	}
                                                    	return EXIT_SUCCESS;
                                                    }
                                                    


                                                    @lithrein: Mon système de justification n'est pas élaboré, et peut-être même un peu trop simple. La différence de performances vient peut-être de là.
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      9 mai 2010 à 14:54:42

                                                      Si je comprend bien, vous envoyez plusieurs fois une petite chaîne à votre zJustificator, c'est ça?

                                                      Je partait sur le principe d'envoyer un fichier énorme, et là ma solution est très pénalisée, sinon dans le cas de petites portions, il n'y a pas de problèmes je pense.

                                                      Avec le texte de Lithrein et 40000 itérations dans un fichier, ma solution met 38 s.

                                                      Celle de Bad_Wolf met 45s et fait crasher l'IDE. :D Je ne vois toujours pas la fuite, pourtant.
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                      Zeste de Savoir, le site qui en a dans le citron !
                                                        9 mai 2010 à 15:02:42

                                                        Citation : Marc Mongenet

                                                        @lithrein: Mon système de justification n'est pas élaboré, et peut-être même un peu trop simple. La différence de performances vient peut-être de là.



                                                        Il me semble avoir compilé en Debug (-g3) mon programme et le tient avec aucune option. Donc peut-être que ça vient de là.
                                                        Je retenterais en compilant avec les optimisations (-O2) pour les deux programmes pour voir ce que cela donne.

                                                        @GurneyH : En fait je fait 400 000 itérations pour le fichier 1.5 Go.

                                                        Edit : j'ai refait un benchmark :
                                                        $ gcc -O2 queue.c main.c -o zJustify
                                                        $ gcc -O2 marc.c -o marc
                                                        $ ./lorem 400000 > input.txt
                                                        
                                                        $ time ./zJustify -c 50 -i input.txt -o output.txt
                                                        
                                                        time    10m43.132s
                                                        user    1m9.199s
                                                        sys     6m56.533s
                                                        
                                                        Taille du fichier en entrée : 1 618 800 640 octets
                                                        Taille du fichier en sortie : 1 727 201 280 octets
                                                        
                                                        $ time ./marc 50 < input.txt > output.txt
                                                        
                                                        time    8m42.225s
                                                        user    0m33.864s
                                                        sys     5m24.132s
                                                        
                                                        Taille du fichier en entrée : 1 618 800 640 octets
                                                        Taille du fichier en sortie : 1 734 000 640 octets
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          9 mai 2010 à 15:07:31

                                                          Citation : GurneyH

                                                          Si je comprend bien, vous envoyez plusieurs fois une petite chaîne à votre zJustificator, c'est ça?


                                                          Non c'est plus simple, mon zJustificator lit stdin jusqu'à EOF.

                                                          Après, c'est une question de commande shell. Sur Unix, si l'on a un fichier de données (disons lorem.txt) et que l'on veut l'envoyer sur le stdin d'un programme (disons ./zJustificator dans le répertoire courant), alors on écrit: ./zJustificator <lorem.txt

                                                          On peut aussi ne pas avoir de fichier de données, et simplement envoyer la sortie (stdout) d'un programme en entrée (stdin) d'un autre programme. On utilise alors un pipe («tuyau» en anglais). Ainsi dans la commande shell ./lorem 1234 | ./zJustificator la sortie du programme ./lorem est envoyée en entrée au programme ./zJustificator.
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            31 mai 2010 à 18:36:18

                                                            Longtemps après la bataille, pouet débarque. :D
                                                            Voilà mon implémentation :

                                                            #include <stdio.h>
                                                            #include <stdlib.h>
                                                            #include <ctype.h>
                                                            #include <sys/queue.h>
                                                            
                                                            typedef struct llist {
                                                              int nb_car;
                                                              char * mot;
                                                              STAILQ_ENTRY(llist) suiv;
                                                            } llist;
                                                            
                                                            STAILQ_HEAD(fifo, llist) tete = STAILQ_HEAD_INITIALIZER(tete);
                                                            
                                                            typedef struct mots_lets_s {
                                                              int nb_mots;
                                                              int nb_lets;
                                                            } mots_lets;
                                                            
                                                            llist * get_mot(int n, FILE * in) {
                                                              llist * p = malloc(sizeof *p);
                                                              char * s = malloc(sizeof *s * (n+1));
                                                              int c, i;
                                                              
                                                              if (p == NULL || s == NULL || in == NULL)
                                                                return NULL;
                                                              
                                                              for (i = 0; i < n; i++) {
                                                                c = getc(in);
                                                                if (isspace(c)) {
                                                                  if (i == 0) {
                                                                    i--;
                                                                    continue;
                                                                  }
                                                                  else
                                                                    break;
                                                                }
                                                                if (c == EOF)
                                                                  break;
                                                                s[i] = c;
                                                              }
                                                              
                                                              if (i == n) {
                                                                ungetc(c, in);
                                                                s[i-1] = '-';
                                                              }
                                                              s[i] = '\0';
                                                              p->mot = s;
                                                              p->nb_car = i;
                                                              
                                                              if (i == 0) {
                                                                free(s);
                                                                free(p);
                                                                p = NULL;
                                                              }
                                                              
                                                              return p;
                                                            }
                                                            
                                                            void verifie_nb(mots_lets * ml, int n) {
                                                              int i;
                                                              llist * p;
                                                              
                                                              p = STAILQ_FIRST(&tete);
                                                              for (i = 0; i < n; i++)
                                                                p = STAILQ_NEXT(p, suiv);
                                                              
                                                              ml->nb_lets -= p->nb_car;
                                                              ml->nb_mots--;
                                                            }
                                                            
                                                            mots_lets get_n_mot(int n, FILE * in) {
                                                              mots_lets ml = { 0, 0 };
                                                              llist * p;
                                                              
                                                              STAILQ_FOREACH(p, &tete, suiv) {
                                                                ml.nb_mots++;
                                                                ml.nb_lets += p->nb_car;
                                                              }
                                                              
                                                              while (ml.nb_lets < n && !feof(in)) {
                                                                p = get_mot(n, in);
                                                                if (p == NULL)
                                                                  break;
                                                                STAILQ_INSERT_TAIL(&tete, p, suiv);
                                                                ml.nb_lets += p->nb_car;
                                                                ml.nb_mots++;
                                                              }
                                                              
                                                              if (ml.nb_lets > n)
                                                                verifie_nb(&ml, ml.nb_mots-1);
                                                              if (ml.nb_mots != 1 && ml.nb_lets + ml.nb_mots - 1 > n)
                                                                verifie_nb(&ml, ml.nb_mots-1);
                                                              
                                                              return ml;
                                                            }
                                                            
                                                            void justifie(int n, mots_lets ml, FILE * out) {
                                                              ldiv_t divi;
                                                              llist * p;
                                                              int i, j;
                                                              
                                                              if (ml.nb_mots == 1) {
                                                                divi.quot = n - ml.nb_lets;
                                                                divi.rem = 0;
                                                              }
                                                              else {
                                                                divi = ldiv(n-ml.nb_lets, ml.nb_mots-1);
                                                              }
                                                              
                                                              for (j = 0; j < ml.nb_mots; j++) {
                                                                p = STAILQ_FIRST(&tete);
                                                                if (p == NULL)
                                                                  return;
                                                                fprintf(out, "%s", p->mot);
                                                                STAILQ_REMOVE_HEAD(&tete, suiv);
                                                                if (divi.rem > 0) {
                                                                  putc(' ', out);
                                                                  divi.rem--;
                                                                }
                                                                if (j != ml.nb_mots-1 || ml.nb_mots == 1)
                                                                  for (i = 0; i < divi.quot; i++)
                                                                    putc(' ', out);
                                                                
                                                              }
                                                              puts("");
                                                            }
                                                            
                                                            int zJustificator(int n, FILE * in, FILE * out) {
                                                              mots_lets ml;
                                                              
                                                              STAILQ_INIT(&tete);
                                                              
                                                              if (!in || !out || n <= 1)
                                                                return -1;
                                                              
                                                              do {
                                                                ml = get_n_mot(n, in);
                                                                justifie(n, ml, out);
                                                              } while (ml.nb_mots != 0);
                                                              
                                                              STAILQ_INIT(&tete);
                                                              return 0;
                                                            }
                                                            
                                                            int main(void) {
                                                              int n = 50;
                                                              FILE * in = fopen("test.txt", "r");
                                                              zJustificator(n, in, stdout);
                                                              if (in)
                                                                fclose(in);
                                                              return EXIT_SUCCESS;
                                                            }
                                                            

                                                            Je pense que je me casse la tête un peu trop pour certaines choses. :-°
                                                            Vos impression ? :)
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                              31 mai 2010 à 20:21:58

                                                              Citation : Pouet_forever

                                                              Vos impression ? :)


                                                              Mitigées...

                                                              20:18:50 /tmp gcc -Wall c.c
                                                              20:19:12 /tmp ./a.out 
                                                              Erreur de segmentation
                                                              20:19:20 /tmp cat >test.txt
                                                              hello, world!
                                                              How are you Mister Bond?
                                                              Fine, thanks!
                                                              20:20:13 /tmp ./a.out 
                                                              hello,  world!  How  are  you  Mister  Bond? Fine,
                                                              20:20:15 /tmp
                                                              • Partager sur Facebook
                                                              • Partager sur Twitter

                                                              zJustificator

                                                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                              • Editeur
                                                              • Markdown