Task: Password generator

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

#define DEFAULT_LENGTH 4
#define DEFAULT_COUNT 1

char* symbols[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz", "0123456789", "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"};
int length = DEFAULT_LENGTH;
int count = DEFAULT_COUNT;
unsigned seed;
char exSymbols = 0;

void GetPassword () {
    
    int lengths[4] = {1, 1, 1, 1};
    int count = 4;
    while (count < length) {
        lengths[rand()%4]++;
        count++;
    } 

    
    char password[length + 1];
    for (int i = 0; i < length; ) { 
        
        int str = rand()%4;
        if (!lengths[str])continue;   

        char c;
        switch (str) {
            case 2:
                c = symbols[str][rand()%10];
                while (exSymbols && (c == 'I' || c == 'l' || c == '1' || c == 'O' || c == '0' || c == '5' || c == 'S' || c == '2' || c == 'Z'))
                    c = symbols[str][rand()%10];
                password[i] = c;
            break;

            case 3:
                c = symbols[str][rand()%30];
                while (exSymbols && (c == 'I' || c == 'l' || c == '1' || c == 'O' || c == '0' || c == '5' || c == 'S' || c == '2' || c == 'Z'))
                    c = symbols[str][rand()%30];
                password[i] = c;
            break;

            default:
                c = symbols[str][rand()%26];
                while (exSymbols && (c == 'I' || c == 'l' || c == '1' || c == 'O' || c == '0' || c == '5' || c == 'S' || c == '2' || c == 'Z'))  
                    c = symbols[str][rand()%26];
                password[i] = c;
            break;
        }

        i++;
        lengths[str]--;
    }

    password [length] = '\0';
    printf ("%s\n", password);
}

int main (int argc, char* argv[]) {
    seed = (unsigned)time(NULL);

    
    for (int i = 1; i < argc; i++) {
        switch (argv[i][1]) {
            case 'l':
                if (sscanf (argv[i+1], "%d", &length) != 1) {
                    puts ("Unrecognized input. Syntax: -l [integer]");
                    return -1;
                }
                
                if (length < 4) {
                    puts ("Password length must be at least 4 characters.");
                    return -1;
                }
                i++;                
            break;

            case 'c':
                if (sscanf (argv[i+1], "%d", &count) != 1) {
                    puts ("Unrecognized input. Syntax: -c [integer]");
                    return -1;
                }

                if (count <= 0) {
                    puts ("Count must be at least 1.");
                    return -1;
                }
                i++;
            break;

            case 's':
                if (sscanf (argv[i+1], "%d", &seed) != 1) {
                    puts ("Unrecognized input. Syntax: -s [integer]");
                    return -1;
                }
                i++;
            break;

            case 'e':
                exSymbols = 1;
            break;

            default:
                help:
                printf ("Help:\nThis program generates a random password.\n"
                "Commands:"
                   "Set password length: -l [integer]\n"
                   "Set password count: -c [integer]\n"
                   "Set seed: -s [integer]\n"
                   "Exclude similiar characters: -e\n"
                   "Display help: -h");
                return 0;
            break;
        }    
    }

    srand (seed);

    for (int i = 0; i < count; i++)
        GetPassword();
    
    return 0;
}











Ada: with Ada.Numerics.Discrete_Random;
with Ada.Strings.Fixed;
with Ada.Command_Line;
with Ada.Integer_Text_IO;
with Ada.Text_IO;

procedure Mkpw is

   procedure Put_Usage;
   procedure Parse_Command_Line (Success : out Boolean);
   function Create_Password (Length : in Positive;
                             Safe   : in Boolean)
                            return String;

   procedure Put_Usage is
      use Ada.Text_IO;
   begin
      Put_Line ("Usage:                                                     ");
      Put_Line ("   mkpw help   - Show this help text                       ");
      Put_Line ("   mkpw [count <n>] [length <l>] [seed 
] [safe]         ");
      Put_Line ("     count <n>  - Number of passwords generated (default 4)");
      Put_Line ("     length <l> - Password length (min 4)       (default 4)");
      Put_Line ("     seed <l>   - Seed for random generator     (default 0)");
      Put_Line ("     safe       - Do not use unsafe characters  (0O1lIS52Z)");
   end Put_Usage;

   Lower_Set  : constant String := "abcdefghijklmnopqrstuvwxyz";
   Upper_Set  : constant String := "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   Digit_Set  : constant String := "0123456789";
   Spec_Set   : constant String := "!""#$%&'()*+,-./:;<=>?@[]^_{|}~";
   Unsafe_Set : constant String := "0O1lI5S2Z";

   Full_Set : constant String := Lower_Set & Upper_Set & Digit_Set & Spec_Set;
   subtype Full_Indices is Positive range Full_Set'Range;

   package Full_Index_Generator is
      new Ada.Numerics.Discrete_Random (Full_Indices);

   Index_Generator : Full_Index_Generator.Generator;

   Config_Safe          : Boolean  := False;
   Config_Count         : Natural  := 4;
   Config_Length        : Positive := 6;
   Config_Seed          : Integer  := 0;
   Config_Show_Help     : Boolean  := False;

   procedure Parse_Command_Line (Success : out Boolean) is
      use Ada.Command_Line;
      Got_Safe,   Got_Count : Boolean  := False;
      Got_Length, Got_Seed  : Boolean  := False;
      Last       : Positive;
      Index      : Positive := 1;
   begin
      Success := False;
      if Argument_Count = 1 and then Argument (1) = "help" then
         Config_Show_Help := True;
         return;
      end if;

      while Index <= Argument_Count loop
         if Ada.Command_Line.Argument (Index) = "safe" then
            if Got_Safe then
               return;
            end if;
            Got_Safe := True;
            Config_Safe     := True;
            Index := Index + 1;
         elsif Argument (Index) = "count" then
            if Got_Count then
               return;
            end if;
            Got_Count := True;
            Ada.Integer_Text_IO.Get (Item => Config_Count,
                                     From => Argument (Index + 1),
                                     Last => Last);
            if Last /= Argument (Index + 1)'Last then
               return;
            end if;
            Index := Index + 2;
         elsif Argument (Index) = "length" then
            if Got_Length then
               return;
            end if;
            Got_Length := True;
            Ada.Integer_Text_IO.Get (Item => Config_Length,
                                     From => Argument (Index + 1),
                                     Last => Last);
            if Last /= Argument (Index + 1)'Last then
               return;
            end if;
            if Config_Length < 4 then
               return;
            end if;
            Index := Index + 2;
         elsif Argument (Index) = "seed" then
            if Got_Seed then
               return;
            end if;
            Got_Seed := True;
            Ada.Integer_Text_IO.Get (Item => Config_Seed,
                                     From => Argument (Index + 1),
                                     Last => Last);
            if Last /= Argument (Index + 1)'Last then
               return;
            end if;
            Index := Index + 2;
         else
            return;
         end if;
      end loop;
      Success := True;
   exception
      when Constraint_Error | Ada.Text_IO.Data_Error =>
         null;
   end Parse_Command_Line;

   function Create_Password (Length : in Positive;
                             Safe   : in Boolean)
                            return String
   is

      function Get_Random (Safe : in Boolean)
                          return Character;

      function Get_Random (Safe : in Boolean)
                          return Character
      is
         use Ada.Strings.Fixed;
         C : Character;
      begin
         loop
            C := Full_Set (Full_Index_Generator.Random (Index_Generator));
            if Safe then
               exit when Index (Source => Unsafe_Set, Pattern => "" & C) = 0;
            else
               exit;
            end if;
         end loop;
         return C;
      end Get_Random;

      function Has_Four (Item : in String)
                        return Boolean;

      function Has_Four (Item : in String)
                        return Boolean
      is
         use Ada.Strings.Fixed;
         Has_Upper, Has_Lower : Boolean := False;
         Has_Digit, Has_Spec  : Boolean := False;
      begin
         for C of Item loop
            if Index (Upper_Set, "" & C) /= 0 then Has_Upper := True; end if;
            if Index (Lower_Set, "" & C) /= 0 then Has_Lower := True; end if;
            if Index (Digit_Set, "" & C) /= 0 then Has_Digit := True; end if;
            if Index (Spec_Set,  "" & C) /= 0 then Has_Spec  := True; end if;
         end loop;
         return Has_Upper and Has_Lower and Has_Digit and Has_Spec;
      end Has_Four;

      Password : String (1 .. Length);
   begin
      loop
         for I in Password'Range loop
            Password (I) := Get_Random (Safe);
         end loop;
         exit when Has_Four (Password);
      end loop;
      return Password;
   end Create_Password;

   Parse_Success : Boolean;
begin

   Parse_Command_Line (Parse_Success);

   if Config_Show_Help or not Parse_Success then
      Put_Usage;  return;
   end if;

   if Config_Seed = 0 then
      Full_Index_Generator.Reset (Index_Generator);
   else
      Full_Index_Generator.Reset (Index_Generator, Config_Seed);
   end if;

   for Count in 1 .. Config_Count loop
      Ada.Text_IO.Put_Line (Create_Password (Length => Config_Length,
                                             Safe   => Config_Safe));
   end loop;

end Mkpw;