Task: Password generator


C++: #include <iostream>
#include <string>
#include <algorithm>
#include <ctime>

const std::string CHR[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz", 
                            "0123456789", "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~" };
const std::string UNS = "O0l1I5S2Z";

std::string createPW( int len, bool safe ) {
    std::string pw;
    char t;
    for( int x = 0; x < len; x += 4 ) {
        for( int y = x; y < x + 4 && y < len; y++ ) {
            do {
                t = CHR[y % 4].at( rand() % CHR[y % 4].size() );
            } while( safe && UNS.find( t ) != UNS.npos );
            pw.append( 1, t );
        }
    }
    std::random_shuffle( pw.begin(), pw.end() );
    return pw;
}
void generate( int len, int count, bool safe ) {
    for( int c = 0; c < count; c++ ) {
        std::cout << createPW( len, safe ) << "\n";
    }
    std::cout << "\n\n";
}
int main( int argc, char* argv[] ){
    if( argv[1][1] == '?' || argc < 5 ) {
        std::cout << "Syntax: PWGEN length count safe seed /?\n"
                     "length:\tthe length of the password(min 4)\n"
                     "count:\thow many passwords should be generated\n"
                     "safe:\t1 will exclude visually similar characters, 0 won't\n"
                     "seed:\tnumber to seed the random generator or 0\n"
                     "/?\tthis text\n\n";
    } else {
        int l = atoi( argv[1] ),
            c = atoi( argv[2] ),
            e = atoi( argv[3] ), 
            s = atoi( argv[4] );
        if( l < 4 ) {
            std::cout << "Passwords must be at least 4 characters long.\n\n";
        } else {
            if (s == 0) {
               std::srand( time( NULL ) );
            } else {
               std::srand( unsigned( s ) );
            }
            generate( l, c, e != 0 );
        }
    }
    return 0;   
}


C#: using System;
using System.Linq;

class Program
{
    const string Lower = "abcdefghijklmnopqrstuvwxyz";
    const string Upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const string Digits = "0123456789";
    const string Symbols = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~";
    static readonly string[] Full = {Lower, Upper, Digits, Symbols, Lower + Upper + Digits + Symbols};

    const string Similar = "Il1O05S2Z";
    static readonly string[] Excluded = Full.Select(x => new string(x.Except(Similar).ToArray())).ToArray();

    static Random _rng = new Random();
    static string[] _symbolSet = Full;

    static void Main(string[] args)
    {
        int length = 12, count = 1;
        try
        {
            foreach (var x in args.Select(arg => arg.Split(':')))
            {
                switch (x[0])
                {
                    case "-l": length = int.Parse(x[1]); break;
                    case "-c": count = int.Parse(x[1]); break;
                    case "-s": _rng = new Random(x[1].GetHashCode()); break;
                    case "-x": _symbolSet = bool.Parse(x[1]) ? Excluded : Full; break;
                    default: throw new FormatException("Could not parse arguments");
                }
            }
        }
        catch { ShowUsage(); return; }
        try
        {
            for (int i = 0; i < count; i++)
                Console.WriteLine(GeneratePass(length));
        }
        catch (Exception ex) { Console.WriteLine("Error: " + ex.Message); }
    }

    static void ShowUsage()
    {
        Console.WriteLine("Usage: PASSGEN [-l:length] [-c:count] [-s:seed] [-x:(true|false)]");
        Console.WriteLine("\t-l: the length of the generated passwords");
        Console.WriteLine("\t-c: the number of passwords to generate");
        Console.WriteLine("\t-s: seed for the random number generator");
        Console.WriteLine("\t-x: exclude similar characters: " + Similar);
        Console.WriteLine("Example: PASSGEN -l:10 -c:5 -s:\"Sample Seed\" -x:true");
    }

    static string GeneratePass(int length)
    {
        var minLength = _symbolSet.Length - 1;
        if(length < minLength)
            throw new Exception("password length must be " + minLength + " or greater");

        int[] usesRemaining = Enumerable.Repeat(1, _symbolSet.Length).ToArray();
        usesRemaining[minLength] = length - minLength;
        var password = new char[length];
        for (int ii = 0; ii < length; ii++)
        {
            int set = _rng.Next(0, _symbolSet.Length);
            if (usesRemaining[set] > 0)
            {
                usesRemaining[set]--;
                password[ii] = _symbolSet[set][_rng.Next(0, _symbolSet[set].Length)];
            }
            else ii--;
        }
        return new string(password);
    }
}