/* This is m3u rand version 0.1 GNU GPL protected. See COPYRIGHT file
 * for details. Send bug reports and suggestions to the author:
 *
 * (C) Copyright 2001 zhaoway <zw@debian.org>
 *
 * This program randomizes lines read from stdin then writes resulted
 * lines to stdout.
 */

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

struct item {
  char *str;
  struct item *next;
  struct item *prev;
} *first;

/* count the lines */
int lines;

void die(char *str)
{
  fprintf(stderr, "m3u-rand: die! %s\n", str);
  exit(1);
}

void read_items(void)
{
  struct item *last, *this;
  size_t zero = 0;

  lines = 0;
  first = (struct item *) malloc(sizeof(struct item));
  if (first == NULL) die("not enough memory!");
  first->str = NULL;
  first->next = first;
  first->prev = first;
  this = first;
  last = NULL;

  /* getline() is _GNU_SOURCE */
  while (getline(&(this->str), &zero, stdin) != -1)
    {
      if (last != NULL) last->next = this;
      last = this;
      this = (struct item *) malloc(sizeof(struct item));
      if (this == NULL) die("not enough memory!");
      this->str = NULL;
      this->next = first;
      this->prev = last;
      lines++;
    }

  first->prev = last;
  free(this);
}

void disp_items(void)
{
  struct item *this;
  int count = lines;

  if (first == NULL) return;
  else this = first;

  while (count-- > 0)
    {
      printf("%s", this->str);
      this = this->next;
    }
}

void rand_items(void)
{
  int num, count = lines;
  struct item *this, *last = NULL;

  if (first == NULL) return;
  else this = first;
  srand(time(0));

  while (count > 0)
    {
      num = rand() % count--;
      while (num-- > 0) this = this->next;
      this->prev->next = this->next;
      this->next->prev = this->prev;

      if (last != NULL)
	{
	  last->next = this;
	  this->prev = last;
	}
      else first = this;

      last = this;
      this = this->next;
    }

  first->prev = last;
  if (last != NULL) last->next = first;
}

int main(int argc, char *argv[])
{
  read_items();
  rand_items();
  disp_items();
  return(0);
}
