WeixiangYan/CodeTransOcean huggingface dataset:
Task: Repeat




Go: package main

import "fmt"

func repeat(n int, f func()) {
  for i := 0; i < n; i++ {
    f()
  }
}

func fn() {
  fmt.Println("Example")
}

func main() {
  repeat(4, fn)
}
Task: Stream merge

C: 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

#define GET(N) { if(fscanf(f##N,"%d",&b##N ) != 1) f##N = NULL; }
#define PUT(N) { printf("%d\n", b##N); GET(N) }

void merge(FILE* f1, FILE* f2, FILE* out)
{
    int b1;
    int b2;

    if(f1) GET(1)
    if(f2) GET(2)

    while ( f1 && f2 )
    {
        if ( b1 <= b2 ) PUT(1)
        else            PUT(2)
    }
    while (f1 ) PUT(1)
    while (f2 ) PUT(2)
}

int main(int argc, char* argv[])
{
    if ( argc < 3 || argc > 3 )
    {
        puts("streammerge filename1 filename2");
        exit(EXIT_FAILURE);
    }
    else
        merge(fopen(argv[1],"r"),fopen(argv[2],"r"),stdout);

    return EXIT_SUCCESS;
}











Ada: with Ada.Text_Io;
with Ada.Command_Line;
with Ada.Containers.Indefinite_Holders;

procedure Stream_Merge is

   package String_Holders
   is new Ada.Containers.Indefinite_Holders (String);

   use Ada.Text_Io, String_Holders;

   type Stream_Type is
      record
         File  : File_Type;
         Value : Holder;
      end record;

   subtype Index_Type is Positive range 1 .. Ada.Command_Line.Argument_Count;
   Streams : array (Index_Type) of Stream_Type;

   procedure Fetch (Stream : in out Stream_Type) is
   begin
      Stream.Value := (if End_Of_File (Stream.File)
                       then Empty_Holder
                       else To_Holder (Get_Line (Stream.File)));
   end Fetch;

   function Next_Stream return Index_Type is
      Index : Index_Type := Index_Type'First;
      Value : Holder;
   begin
      for I in Streams'Range loop
         if Value.Is_Empty and not Streams (I).Value.Is_Empty then
            Value := Streams (I).Value;
            Index := I;
         elsif not Streams (I).Value.Is_Empty and then Streams (I).Value.Element < Value.Element then
            Value := Streams (I).Value;
            Index := I;
         end if;
      end loop;
      if Value.Is_Empty then
         raise Program_Error;
      end if;
      return Index;
   end Next_Stream;

   function More_Data return Boolean
   is (for some Stream of Streams => not Stream.Value.Is_Empty);

begin

   if Ada.Command_Line.Argument_Count = 0 then
      Put_Line ("Usage: prog <file1> <file2> ...");
      Put_Line ("Merge the sorted files file1, file2...");
      return;
   end if;

   for I in Streams'Range loop
      Open (Streams (I).File, In_File, Ada.Command_Line.Argument (I));
      Fetch (Streams (I));
   end loop;

   while More_Data loop
      declare
         Stream : Stream_Type renames Streams (Next_Stream);
      begin
         Put_Line (Stream.Value.Element);
         Fetch (Stream);
      end;
   end loop;

end Stream_Merge;
Task: Stream merge







Python: import heapq
import sys

sources = sys.argv[1:]
for item in heapq.merge(open(source) for source in sources):
    print(item)





Ada: with Ada.Text_Io;
with Ada.Command_Line;
with Ada.Containers.Indefinite_Holders;

procedure Stream_Merge is

   package String_Holders
   is new Ada.Containers.Indefinite_Holders (String);

   use Ada.Text_Io, String_Holders;

   type Stream_Type is
      record
         File  : File_Type;
         Value : Holder;
      end record;

   subtype Index_Type is Positive range 1 .. Ada.Command_Line.Argument_Count;
   Streams : array (Index_Type) of Stream_Type;

   procedure Fetch (Stream : in out Stream_Type) is
   begin
      Stream.Value := (if End_Of_File (Stream.File)
                       then Empty_Holder
                       else To_Holder (Get_Line (Stream.File)));
   end Fetch;

   function Next_Stream return Index_Type is
      Index : Index_Type := Index_Type'First;
      Value : Holder;
   begin
      for I in Streams'Range loop
         if Value.Is_Empty and not Streams (I).Value.Is_Empty then
            Value := Streams (I).Value;
            Index := I;
         elsif not Streams (I).Value.Is_Empty and then Streams (I).Value.Element < Value.Element then
            Value := Streams (I).Value;
            Index := I;
         end if;
      end loop;
      if Value.Is_Empty then
         raise Program_Error;
      end if;
      return Index;
   end Next_Stream;

   function More_Data return Boolean
   is (for some Stream of Streams => not Stream.Value.Is_Empty);

begin

   if Ada.Command_Line.Argument_Count = 0 then
      Put_Line ("Usage: prog <file1> <file2> ...");
      Put_Line ("Merge the sorted files file1, file2...");
      return;
   end if;

   for I in Streams'Range loop
      Open (Streams (I).File, In_File, Ada.Command_Line.Argument (I));
      Fetch (Streams (I));
   end loop;

   while More_Data loop
      declare
         Stream : Stream_Type renames Streams (Next_Stream);
      begin
         Put_Line (Stream.Value.Element);
         Fetch (Stream);
      end;
   end loop;

end Stream_Merge;
Task: Stream merge

C: 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

#define GET(N) { if(fscanf(f##N,"%d",&b##N ) != 1) f##N = NULL; }
#define PUT(N) { printf("%d\n", b##N); GET(N) }

void merge(FILE* f1, FILE* f2, FILE* out)
{
    int b1;
    int b2;

    if(f1) GET(1)
    if(f2) GET(2)

    while ( f1 && f2 )
    {
        if ( b1 <= b2 ) PUT(1)
        else            PUT(2)
    }
    while (f1 ) PUT(1)
    while (f2 ) PUT(2)
}

int main(int argc, char* argv[])
{
    if ( argc < 3 || argc > 3 )
    {
        puts("streammerge filename1 filename2");
        exit(EXIT_FAILURE);
    }
    else
        merge(fopen(argv[1],"r"),fopen(argv[2],"r"),stdout);

    return EXIT_SUCCESS;
}
Task: Stream merge



C#: using System;
using System.Collections.Generic;
using System.Linq;

namespace RosettaCode
{
    static class StreamMerge
    {
        static IEnumerable<T> Merge2<T>(IEnumerable<T> source1, IEnumerable<T> source2) where T : IComparable
        {
            var q1 = new Queue<T>(source1);
            var q2 = new Queue<T>(source2);
            while (q1.Any() && q2.Any())
            {
                var c = q1.Peek().CompareTo(q2.Peek());
                if (c <= 0) yield return q1.Dequeue(); else yield return q2.Dequeue();
            }
            while (q1.Any()) yield return q1.Dequeue();
            while (q2.Any()) yield return q2.Dequeue();
        }

        static IEnumerable<T> MergeN<T>(params IEnumerable<T>[] sources) where T : IComparable
        {
            var queues = sources.Select(e => new Queue<T>(e)).Where(q => q.Any()).ToList();
            var headComparer = Comparer<Queue<T>>.Create((x, y) => x.Peek().CompareTo(y.Peek()));
            queues.Sort(headComparer);
            
            while (queues.Any())
            {
                var q = queues.First();
                queues.RemoveAt(0);
                yield return q.Dequeue();
                if (q.Any())
                {
                    var index = queues.BinarySearch(q, headComparer);
                    queues.Insert(index < 0 ? ~index : index, q);
                }
            }
        }

        static void Main()
        {
            var a = new[] { 1, 4, 7, 10 };
            var b = new[] { 2, 5, 8, 11 };
            var c = new[] { 3, 6, 9, 12 };

            foreach (var i in Merge2(a, b)) Console.Write($"{i} ");
            Console.WriteLine();

            foreach (var i in MergeN(a, b, c)) Console.Write($"{i} ");
            Console.WriteLine();
        }
    }
}
Task: Stream merge


C++: 
#include <iostream>
#include <vector>

template <typename C, typename A>
void merge2(const C& c1, const C& c2, const A& action) {
    auto i1 = std::cbegin(c1);
    auto i2 = std::cbegin(c2);

    while (i1 != std::cend(c1) && i2 != std::cend(c2)) {
        if (*i1 <= *i2) {
            action(*i1);
            i1 = std::next(i1);
        } else {
            action(*i2);
            i2 = std::next(i2);
        }
    }
    while (i1 != std::cend(c1)) {
        action(*i1);
        i1 = std::next(i1);
    }
    while (i2 != std::cend(c2)) {
        action(*i2);
        i2 = std::next(i2);
    }
}

template <typename A, typename C>
void mergeN(const A& action, std::initializer_list<C> all) {
    using I = typename C::const_iterator;
    using R = std::pair<I, I>;

    std::vector<R> vit;
    for (auto& c : all) {
        auto p = std::make_pair(std::cbegin(c), std::cend(c));
        vit.push_back(p);
    }

    bool done;
    R* least;
    do {
        done = true;

        auto it = vit.begin();
        auto end = vit.end();
        least = nullptr;

        
        while (it != end && it->first == it->second) {
            it++;
        }
        if (it != end) {
            least = &(*it);
        }
        while (it != end) {
            
            while (it != end && it->first == it->second) {
                it++;
            }
            if (least != nullptr && it != end
                && it->first != it->second
                && *(it->first) < *(least->first)) {
                
                least = &(*it);
            }
            if (it != end) {
                it++;
            }
        }
        if (least != nullptr && least->first != least->second) {
            done = false;
            action(*(least->first));
            least->first = std::next(least->first);
        }
    } while (!done);
}

void display(int num) {
    std::cout << num << ' ';
}

int main() {
    std::vector<int> v1{ 0, 3, 6 };
    std::vector<int> v2{ 1, 4, 7 };
    std::vector<int> v3{ 2, 5, 8 };

    merge2(v2, v1, display);
    std::cout << '\n';

    mergeN(display, { v1 });
    std::cout << '\n';

    mergeN(display, { v3, v2, v1 });
    std::cout << '\n';
}
Task: Stream merge





Java: import java.util.Iterator;
import java.util.List;
import java.util.Objects;

public class StreamMerge {
    private static <T extends Comparable<T>> void merge2(Iterator<T> i1, Iterator<T> i2) {
        T a = null, b = null;

        while (i1.hasNext() || i2.hasNext()) {
            if (null == a && i1.hasNext()) {
                a = i1.next();
            }
            if (null == b && i2.hasNext()) {
                b = i2.next();
            }

            if (null != a) {
                if (null != b) {
                    if (a.compareTo(b) < 0) {
                        System.out.print(a);
                        a = null;
                    } else {
                        System.out.print(b);
                        b = null;
                    }
                } else {
                    System.out.print(a);
                    a = null;
                }
            } else if (null != b) {
                System.out.print(b);
                b = null;
            }
        }

        if (null != a) {
            System.out.print(a);
        }
        if (null != b) {
            System.out.print(b);
        }
    }

    @SuppressWarnings("unchecked")
    @SafeVarargs
    private static <T extends Comparable<T>> void mergeN(Iterator<T>... iter) {
        Objects.requireNonNull(iter);
        if (iter.length == 0) {
            throw new IllegalArgumentException("Must have at least one iterator");
        }

        Object[] pa = new Object[iter.length];
        boolean done;

        do {
            done = true;

            for (int i = 0; i < iter.length; i++) {
                Iterator<T> t = iter[i];
                if (null == pa[i] && t.hasNext()) {
                    pa[i] = t.next();
                }
            }

            T min = null;
            int idx = -1;
            for (int i = 0; i < pa.length; ++i) {
                T t = (T) pa[i];
                if (null != t) {
                    if (null == min) {
                        min = t;
                        idx = i;
                        done = false;
                    } else if (t.compareTo(min) < 0) {
                        min = t;
                        idx = i;
                        done = false;
                    }
                }
            }
            if (idx != -1) {
                System.out.print(min);
                pa[idx] = null;
            }
        } while (!done);
    }

    public static void main(String[] args) {
        List<Integer> l1 = List.of(1, 4, 7, 10);
        List<Integer> l2 = List.of(2, 5, 8, 11);
        List<Integer> l3 = List.of(3, 6, 9, 12);

        merge2(l1.iterator(), l2.iterator());
        System.out.println();

        mergeN(l1.iterator(), l2.iterator(), l3.iterator());
        System.out.println();
        System.out.flush();
    }
}
Task: Stream merge







Python: import heapq
import sys

sources = sys.argv[1:]
for item in heapq.merge(open(source) for source in sources):
    print(item)
Task: Stream merge




Go: package main

import (
    "container/heap"
    "fmt"
    "io"
    "log"
    "os"
    "strings"
)

var s1 = "3 14 15"
var s2 = "2 17 18"
var s3 = ""
var s4 = "2 3 5 7"

func main() {
    fmt.Print("merge2: ")
    merge2(
        os.Stdout,
        strings.NewReader(s1),
        strings.NewReader(s2))
    fmt.Println()

    fmt.Print("mergeN: ")
    mergeN(
        os.Stdout,
        strings.NewReader(s1),
        strings.NewReader(s2),
        strings.NewReader(s3),
        strings.NewReader(s4))
    fmt.Println()
}

func r1(r io.Reader) (v int, ok bool) {
    switch _, err := fmt.Fscan(r, &v); {
    case err == nil:
        return v, true
    case err != io.EOF:
        log.Fatal(err)
    }
    return
}

func merge2(m io.Writer, s1, s2 io.Reader) {
    v1, d1 := r1(s1)
    v2, d2 := r1(s2)
    var v int
    for d1 || d2 {
        if !d2 || d1 && v1 < v2 {
            v = v1
            v1, d1 = r1(s1)
        } else {
            v = v2
            v2, d2 = r1(s2)
        }
        fmt.Fprint(m, v, " ")
    }
}

type sv struct {
    s io.Reader
    v int
}

type sh []sv

func (s sh) Len() int            { return len(s) }
func (s sh) Less(i, j int) bool  { return s[i].v < s[j].v }
func (s sh) Swap(i, j int)       { s[i], s[j] = s[j], s[i] }
func (p *sh) Push(x interface{}) { *p = append(*p, x.(sv)) }
func (p *sh) Pop() interface{} {
    s := *p
    last := len(s) - 1
    v := s[last]
    *p = s[:last]
    return v
}

func mergeN(m io.Writer, s ...io.Reader) {
    var h sh
    for _, s := range s {
        if v, d := r1(s); d {
            h = append(h, sv{s, v})
        }
    }
    heap.Init(&h)
    for len(h) > 0 {
        p := heap.Pop(&h).(sv)
        fmt.Fprint(m, p.v, " ")
        if v, d := r1(p.s); d {
            heap.Push(&h, sv{p.s, v})
        }
    }
}
Task: Stream merge

C: 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

#define GET(N) { if(fscanf(f##N,"%d",&b##N ) != 1) f##N = NULL; }
#define PUT(N) { printf("%d\n", b##N); GET(N) }

void merge(FILE* f1, FILE* f2, FILE* out)
{
    int b1;
    int b2;

    if(f1) GET(1)
    if(f2) GET(2)

    while ( f1 && f2 )
    {
        if ( b1 <= b2 ) PUT(1)
        else            PUT(2)
    }
    while (f1 ) PUT(1)
    while (f2 ) PUT(2)
}

int main(int argc, char* argv[])
{
    if ( argc < 3 || argc > 3 )
    {
        puts("streammerge filename1 filename2");
        exit(EXIT_FAILURE);
    }
    else
        merge(fopen(argv[1],"r"),fopen(argv[2],"r"),stdout);

    return EXIT_SUCCESS;
}










Fortran:       SUBROUTINE FILEMERGE(N,INF,OUTF)	
       INTEGER N	
       INTEGER INF(*)	
       INTEGER OUTF	
       INTEGER L(N)	
       INTEGER LIST(0:N)
       LOGICAL LIVE(N)	
       INTEGER ENUFF		
       PARAMETER (ENUFF = 666)	
       CHARACTER*(ENUFF) AREC(N)
       INTEGER I,IT	
        LIST = 0	
        LIVE = .TRUE.	
Charge the battery.
        DO I = 1,N	
          CALL GRAB(I)		
        END DO		
Chug away.
        DO WHILE(LIST(0).GT.0)	
          IT = LIST(0)		
          WRITE (OUTF,"(A)") AREC(IT)(1:L(IT))	
          LIST(0) = LIST(IT)	
          CALL GRAB(IT)		
        END DO			

       CONTAINS	
        SUBROUTINE GRAB(IN)	
         INTEGER IN		
         INTEGER IT,P		
          IF (.NOT.LIVE(IN)) RETURN	
          READ (INF(IN),1,END = 10) L(IN),AREC(IN)(1:MIN(ENUFF,L(IN)))	
    1     FORMAT (Q,A)		
Consider the place of AREC(IN) in the LIST. Entry LIST(IN) is to be linked back in.
          P = 0		
    2     IT = LIST(P)		
          IF (IT.GT.0) THEN	
            IF (AREC(IN)(1:L(IN)).GT.AREC(IT)(1:L(IT))) THEN	
              P = IT			
              GO TO 2			
            END IF		
          END IF	
          LIST(IN) = IT		
          LIST(P) = IN		
          RETURN	
   10     LIVE(IN) = .FALSE.	
          LIST(IN) = -666	
        END SUBROUTINE GRAB	
      END SUBROUTINE FILEMERGE	

      PROGRAM MASH
      INTEGER MANY
      PARAMETER (MANY = 4)	
      INTEGER FI(MANY)
      CHARACTER*(28) FNAME(MANY)
      DATA FNAME/"FileAppend.for","FileChop.for",
     1 "FileExt.for","FileHack.for"/
      INTEGER I,F

      F = 10	
      OPEN (F,FILE="Merged.txt",STATUS="REPLACE",ACTION="WRITE")	
      DO I = 1,MANY	
        FI(I) = F + I		
        OPEN (FI(I),FILE=FNAME(I),STATUS="OLD",ACTION="READ")	
      END DO		

      CALL FILEMERGE(MANY,FI,F)	

      END
Task: Stream merge







Python: import heapq
import sys

sources = sys.argv[1:]
for item in heapq.merge(open(source) for source in sources):
    print(item)




Fortran:       SUBROUTINE FILEMERGE(N,INF,OUTF)	
       INTEGER N	
       INTEGER INF(*)	
       INTEGER OUTF	
       INTEGER L(N)	
       INTEGER LIST(0:N)
       LOGICAL LIVE(N)	
       INTEGER ENUFF		
       PARAMETER (ENUFF = 666)	
       CHARACTER*(ENUFF) AREC(N)
       INTEGER I,IT	
        LIST = 0	
        LIVE = .TRUE.	
Charge the battery.
        DO I = 1,N	
          CALL GRAB(I)		
        END DO		
Chug away.
        DO WHILE(LIST(0).GT.0)	
          IT = LIST(0)		
          WRITE (OUTF,"(A)") AREC(IT)(1:L(IT))	
          LIST(0) = LIST(IT)	
          CALL GRAB(IT)		
        END DO			

       CONTAINS	
        SUBROUTINE GRAB(IN)	
         INTEGER IN		
         INTEGER IT,P		
          IF (.NOT.LIVE(IN)) RETURN	
          READ (INF(IN),1,END = 10) L(IN),AREC(IN)(1:MIN(ENUFF,L(IN)))	
    1     FORMAT (Q,A)		
Consider the place of AREC(IN) in the LIST. Entry LIST(IN) is to be linked back in.
          P = 0		
    2     IT = LIST(P)		
          IF (IT.GT.0) THEN	
            IF (AREC(IN)(1:L(IN)).GT.AREC(IT)(1:L(IT))) THEN	
              P = IT			
              GO TO 2			
            END IF		
          END IF	
          LIST(IN) = IT		
          LIST(P) = IN		
          RETURN	
   10     LIVE(IN) = .FALSE.	
          LIST(IN) = -666	
        END SUBROUTINE GRAB	
      END SUBROUTINE FILEMERGE	

      PROGRAM MASH
      INTEGER MANY
      PARAMETER (MANY = 4)	
      INTEGER FI(MANY)
      CHARACTER*(28) FNAME(MANY)
      DATA FNAME/"FileAppend.for","FileChop.for",
     1 "FileExt.for","FileHack.for"/
      INTEGER I,F

      F = 10	
      OPEN (F,FILE="Merged.txt",STATUS="REPLACE",ACTION="WRITE")	
      DO I = 1,MANY	
        FI(I) = F + I		
        OPEN (FI(I),FILE=FNAME(I),STATUS="OLD",ACTION="READ")	
      END DO		

      CALL FILEMERGE(MANY,FI,F)	

      END
Task: The Twelve Days of Christmas



C#: using System;

public class TwelveDaysOfChristmas {

    public static void Main() {

        string[] days = new string[12] {
            "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth",
            "tenth", "eleventh", "twelfth",
        };

        string[] gifts = new string[12] {
            "A partridge in a pear tree",
            "Two turtle doves",
            "Three french hens",
            "Four calling birds",
            "Five golden rings",
            "Six geese a-laying",
            "Seven swans a-swimming",
            "Eight maids a-milking",
            "Nine ladies dancing",
            "Ten lords a-leaping",
            "Eleven pipers piping",
            "Twelve drummers drumming"
        };

        for ( int i = 0; i < 12; i++ ) {

            Console.WriteLine("On the " + days[i] + " day of Christmas, my true love gave to me");

            int j = i + 1;
            while ( j-- > 0 )
                Console.WriteLine(gifts[j]);

            Console.WriteLine();

            if ( i == 0 )
                gifts[0] = "And a partridge in a pear tree";
        }

    }

}









Ada: with Ada.Text_IO;           use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;

procedure Twelve_Days_Of_Christmas is
   type Days is (First, Second, Third, Fourth, Fifth, Sixth,
		 Seventh, Eighth, Ninth, Tenth, Eleventh, Twelfth);
   
   package E_IO is new Ada.Text_IO.Enumeration_IO(Days);
   use E_IO;
   
   Gifts : array (Days) of Unbounded_String :=
     (To_Unbounded_String(" A partridge in a pear-tree."),
      To_Unbounded_String(" Two turtle doves"),
      To_Unbounded_String(" Three French hens"),
      To_Unbounded_String(" Four calling birds"),
      To_Unbounded_String(" Five golden rings"),
      To_Unbounded_String(" Six geese a-laying"),
      To_Unbounded_String(" Seven swans a-swimming"),
      To_Unbounded_String(" Eight maids a-milking"),
      To_Unbounded_String(" Nine ladies dancing"),
      To_Unbounded_String(" Ten lords a-leaping"),
      To_Unbounded_String(" Eleven pipers piping"),
      To_Unbounded_String(" Twelve drummers drumming"));
begin
   for Day in Days loop
      Put("On the "); Put(Day, Set => Lower_Case); Put(" day of Christmas,");
      New_Line; Put_Line("My true love gave to me:");
      for D in reverse Days'First..Day loop
	 Put_Line(To_String(Gifts(D)));
      end loop;
      if Day = First then
	 Replace_Slice(Gifts(Day), 2, 2, "And a");
      end if;
      New_Line;
   end loop;
end Twelve_Days_Of_Christmas;
Task: The Twelve Days of Christmas

C: #include<stdio.h>
 
int main()
{
    int i,j;
 
    char days[12][10] = 
    {
        "First",
        "Second",
        "Third",
        "Fourth",
        "Fifth",
        "Sixth",
        "Seventh",
        "Eighth",
        "Ninth",
        "Tenth",
        "Eleventh",
        "Twelfth"
    };

    char gifts[12][33] =
    {
        "Twelve drummers drumming",
        "Eleven pipers piping",
        "Ten lords a-leaping",
        "Nine ladies dancing",
        "Eight maids a-milking",
        "Seven swans a-swimming",
        "Six geese a-laying",
        "Five golden rings",
        "Four calling birds",
        "Three french hens", 
        "Two turtle doves", 
        "And a partridge in a pear tree."
    };
 
    for(i=0;i<12;i++)
    {
        printf("\n\nOn the %s day of Christmas\nMy true love gave to me:",days[i]);
 
        for(j=i;j>=0;j--)
        {
            (i==0)?printf("\nA partridge in a pear tree."):printf("\n%s%c",gifts[11-j],(j!=0)?',':' ');
        }
    }
 
    return 0;
}











Ada: with Ada.Text_IO;           use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;

procedure Twelve_Days_Of_Christmas is
   type Days is (First, Second, Third, Fourth, Fifth, Sixth,
		 Seventh, Eighth, Ninth, Tenth, Eleventh, Twelfth);
   
   package E_IO is new Ada.Text_IO.Enumeration_IO(Days);
   use E_IO;
   
   Gifts : array (Days) of Unbounded_String :=
     (To_Unbounded_String(" A partridge in a pear-tree."),
      To_Unbounded_String(" Two turtle doves"),
      To_Unbounded_String(" Three French hens"),
      To_Unbounded_String(" Four calling birds"),
      To_Unbounded_String(" Five golden rings"),
      To_Unbounded_String(" Six geese a-laying"),
      To_Unbounded_String(" Seven swans a-swimming"),
      To_Unbounded_String(" Eight maids a-milking"),
      To_Unbounded_String(" Nine ladies dancing"),
      To_Unbounded_String(" Ten lords a-leaping"),
      To_Unbounded_String(" Eleven pipers piping"),
      To_Unbounded_String(" Twelve drummers drumming"));
begin
   for Day in Days loop
      Put("On the "); Put(Day, Set => Lower_Case); Put(" day of Christmas,");
      New_Line; Put_Line("My true love gave to me:");
      for D in reverse Days'First..Day loop
	 Put_Line(To_String(Gifts(D)));
      end loop;
      if Day = First then
	 Replace_Slice(Gifts(Day), 2, 2, "And a");
      end if;
      New_Line;
   end loop;
end Twelve_Days_Of_Christmas;