mtglist

changeset 0:0a45dfe93e66

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 02 Nov 2014 11:07:45 +0200
parents
children 7211fa8db425
files .hgignore Makefile cardlist editions.cfg src/mtg.c src/mtg.h src/mtglist.c src/rbtree.c src/rbtree.h
diffstat 9 files changed, 1452 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Sun Nov 02 11:07:45 2014 +0200
     1.3 @@ -0,0 +1,4 @@
     1.4 +\.o$
     1.5 +\.swp$
     1.6 +\.d$
     1.7 +^mtglist$
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Makefile	Sun Nov 02 11:07:45 2014 +0200
     2.3 @@ -0,0 +1,12 @@
     2.4 +src = $(wildcard src/*.c)
     2.5 +obj = $(src:.c=.o)
     2.6 +bin = mtglist
     2.7 +
     2.8 +CFLAGS = -pedantic -Wall -g
     2.9 +
    2.10 +$(bin): $(obj)
    2.11 +	$(CC) -o $@ $(obj) $(LDFLAGS)
    2.12 +
    2.13 +.PHONE: clean
    2.14 +clean:
    2.15 +	rm -f $(obj) $(bin)
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/cardlist	Sun Nov 02 11:07:45 2014 +0200
     3.3 @@ -0,0 +1,374 @@
     3.4 +-|Crystal Vein|Land|2|6ed|
     3.5 +-|Geothermal Crevice|Land|1|inv|
     3.6 +-|High Market|Land|1|mmq|foil
     3.7 +-|Mystic Monastery|Land|1|ktk|
     3.8 +-|Sulfur Vent|Land|1|inv|
     3.9 +*|Armadillo Cloak|Enchantment|2|inv|Green/White
    3.10 +*|Aura Mutation|Instant|1|inv|Green/White
    3.11 +*|Battlefield Forge|Land|1|apc|Red/White
    3.12 +*|Captain's Maneuver|Instant|1|apc|Red/White
    3.13 +*|Chief of the Scale|Creature|1|ktk|White/Black
    3.14 +*|Cinder Shade|Creature|1|inv|Black/Red
    3.15 +*|Gaea's Skyfolk|Creature|1|apc|Green/Blue
    3.16 +*|Galina's Knight|Creature|1|inv|White/Blue
    3.17 +*|Hanna, Ship's Navigator|Creature|1|inv|White/Blue
    3.18 +*|Heroes' Reunion|Instant|1|inv|Green/White
    3.19 +*|Jungle Barrier|Creature|1|apc|Green/Blue
    3.20 +*|Jungle Hollow|Land|1|ktk|Black/Green
    3.21 +*|Llanowar Dead|Creature|1|apc|Black/Green
    3.22 +*|Ordered Migration|Sorcery|1|inv|White/Blue
    3.23 +*|Putrid Warrior|Creature|1|apc|White/Black
    3.24 +*|Shivan Zombie|Creature|1|inv|Black/Red
    3.25 +*|Sorin, Solemn Visitor|Planeswalker|1|ktk|White/Black
    3.26 +*|Tainted Field|Land|1|tor|White/Black
    3.27 +*|Temporal Spring|Sorcery|1|apc|Green/Blue
    3.28 +*|Yavimaya Kavu|Creature|1|inv|Red/Green
    3.29 +Artifact|Amulet of Kroog|Artifact|1|5ed|
    3.30 +Artifact|Ashnod's Transmogrant|Artifact|1|5ed|
    3.31 +Artifact|Coiled Tinviper|Creature|1|tmp|
    3.32 +Artifact|Crooked Scales|Artifact|1|mmq|
    3.33 +Artifact|Dancing Scimitar|Creature|1|9ed|
    3.34 +Artifact|Dodecapod|Creature|1|apc|
    3.35 +Artifact|Glasses of Urza|Artifact|1|5ed|
    3.36 +Artifact|Iron Lance|Artifact|1|mmq|
    3.37 +Artifact|Iron Star|Artifact|1|5ed|
    3.38 +Artifact|Ivory Cup|Artifact|1|6ed|
    3.39 +Artifact|Juggernaut|Artifact|1|m15|
    3.40 +Artifact|Patagia Golem|Creature|1|6ed|
    3.41 +Artifact|Rod of Ruin|Artifact|1|9ed|
    3.42 +Artifact|Rusting Golem|Creature|1|nms|
    3.43 +Artifact|Skull Catapult|Artifact|1|5ed|
    3.44 +Artifact|Throne of Bone|Artifact|1|5ed|
    3.45 +Artifact|Tigereye Cameo|Artifact|1|apc|
    3.46 +Artifact|Tyrant's Machine|Artifact|1|m15|foil
    3.47 +Artifact|Urza's Blueprints|Artifact|1|ulg|
    3.48 +Artifact|Wall of Spears|Creature|1|5ed|
    3.49 +Black|Agonizing Demise|Instant|1|inv|
    3.50 +Black|Black Cat|Creature|1|m15|
    3.51 +Black|Blight|Enchantment|1|6ed|
    3.52 +Black|Blood Pet|Creature|1|6ed|
    3.53 +Black|Bog Wraith|Creature|1|5ed|
    3.54 +Black|Bog Wraith|Creature|1|6ed|
    3.55 +Black|Cabal Ritual|Instant|1|tor|
    3.56 +Black|Cackling Witch|Creature|1|mmq|
    3.57 +Black|Carrion Crow|Creature|1|m15|
    3.58 +Black|Cateran Persuader|Creature|1|mmq|
    3.59 +Black|Coercion|Sorcery|1|5ed|
    3.60 +Black|Covenant of Blood|Sorcery|1|m15|
    3.61 +Black|Crypt Sliver|Creature|1|lgn|
    3.62 +Black|Cursed Land|Enchantment|1|5ed|
    3.63 +Black|Dark Banishing|Instant|1|tmp|
    3.64 +Black|Dark Ritual|Instant|1|5ed|
    3.65 +Black|Dark Triumph|Instant|1|nms|
    3.66 +Black|Dauthi Horror|Creature|1|tmp|
    3.67 +Black|Dead Ringers|Sorcery|1|apc|
    3.68 +Black|Despondency|Enchantment|1|usg|
    3.69 +Black|Drain Life|Sorcery|1|5ed|
    3.70 +Black|Fallen Angel|Creature|1|5ed|
    3.71 +Black|Firescreamer|Creature|1|inv|
    3.72 +Black|Frozen Shade|Creature|1|5ed|
    3.73 +Black|Grave Defiler|Creature|1|apc|
    3.74 +Black|Gravebane Zombie|Creature|2|6ed|
    3.75 +Black|Gravedigger|Creature|1|6ed|
    3.76 +Black|Haunted Crossroads|Enchantment|1|mmq|
    3.77 +Black|Krovikan Fetish|Enchantment|1|5ed|
    3.78 +Black|Lost Soul|Creature|1|5ed|
    3.79 +Black|Maggot Therapy|Enchantment|1|mmq|
    3.80 +Black|Mind Extraction|Sorcery|1|apc|
    3.81 +Black|Mind Swords|Sorcery|1|nms|
    3.82 +Black|Necra Disciple|Creature|1|apc|
    3.83 +Black|Nightscape Apprentice|Creature|1|inv|
    3.84 +Black|Phyrexian Slayer|Creature|1|inv|
    3.85 +Black|Putrid Imp|Creature|1|tor|
    3.86 +Black|Python|Creature|2|6ed|
    3.87 +Black|Quagmire Druid|Creature|1|apc|
    3.88 +Black|Razortooth Rats|Creature|1|6ed|
    3.89 +Black|Reckless Spite|Instant|2|inv|
    3.90 +Black|Rouse|Instant|1|mmq|
    3.91 +Black|Scathe Zombies|Creature|1|6ed|
    3.92 +Black|Sever Soul|Sorcery|1|mmq|
    3.93 +Black|Shambling Attendants|Creature|1|ktk|
    3.94 +Black|Skulking Fugitive|Creature|1|mmq|foil
    3.95 +Black|Snuff Out|Instant|1|mmq|
    3.96 +Black|Swamp|Land|18|*|9x5ed,1x6ed,6xinv,2xm15
    3.97 +Black|Syphon Soul|Sorcery|2|6ed|
    3.98 +Black|Terror|Instant|1|5ed|
    3.99 +Black|Undertaker|Creature|1|mmq|
   3.100 +Black|Unmake the Graves|Instant|1|m15|
   3.101 +Black|Vampiric Tutor|Instant|1|6ed|
   3.102 +Black|Vicious Hunger|Sorcery|1|nms|
   3.103 +Black|Vile Deacon|Creature|1|lgn|
   3.104 +Black|Waste Away|Instant|1|tor|
   3.105 +Black|Weakness|Enchantment|1|5ed|
   3.106 +Black|Zombie Master|Creature|1|6ed|
   3.107 +Blue|Barrin's Unmaking|Instant|1|inv|
   3.108 +Blue|Boomerang|Instant|1|5ed|
   3.109 +Blue|Boomerang|Instant|1|6ed|
   3.110 +Blue|Brainstorm|Instant|1|5ed|
   3.111 +Blue|Brainstorm|Instant|1|mmq|
   3.112 +Blue|Buoyancy|Enchantment|1|mmq|
   3.113 +Blue|Cephalid Aristocrat|Creature|1|tor|
   3.114 +Blue|Cephalid Sage|Creature|1|tor|
   3.115 +Blue|Cephalid Snitch|Creature|1|tor|
   3.116 +Blue|Cloud Sprite|Creature|2|mmq|
   3.117 +Blue|Coastal Drake|Creature|1|apc|
   3.118 +Blue|Coral Eel|Creature|2|9ed|
   3.119 +Blue|Counterspell|Instant|1|5ed|
   3.120 +Blue|Dark Maze|Creature|1|5ed|
   3.121 +Blue|Daze|Instant|1|nms|
   3.122 +Blue|Deep Analysis|Sorcery|1|tor|
   3.123 +Blue|Diffusion Sliver|Creature|1|m15|
   3.124 +Blue|Diplomatic Escort|Creature|2|mmq|
   3.125 +Blue|Diplomatic Immunity|Enchantment|1|mmq|
   3.126 +Blue|Dream Thrush|Creature|1|inv|
   3.127 +Blue|Faerie Squadron|Creature|1|inv|
   3.128 +Blue|Flight|Enchantment|1|5ed|
   3.129 +Blue|Fugitive Wizard|Creature|1|9ed|
   3.130 +Blue|Gaseous Form|Enchantment|1|5ed|
   3.131 +Blue|Giant Crab|Creature|1|tmp|
   3.132 +Blue|Giant Octopus|Creature|3|9ed|
   3.133 +Blue|Glacial Crasher|Creature|1|m15|
   3.134 +Blue|Harmattan Efreet|Creature|1|6ed|
   3.135 +Blue|Horned Turtle|Creature|1|6ed|
   3.136 +Blue|Index|Sorcery|1|9ed|
   3.137 +Blue|Inspiration|Instant|2|6ed|
   3.138 +Blue|Invisibility|Enchantment|1|m15|
   3.139 +Blue|Island|Land|22|*|8x5ed,6xinv,8x9ed
   3.140 +Blue|Jeskai Windscout|Creature|1|ktk|
   3.141 +Blue|Jilt|Instant|1|apc|
   3.142 +Blue|Juxtapose|Sorcery|1|5ed|
   3.143 +Blue|Living Airship|Creature|1|apc|
   3.144 +Blue|Manipulate Fate|Sorcery|2|inv|
   3.145 +Blue|Memory Lapse|Instant|1|5ed|
   3.146 +Blue|Mind Bomb|Sorcery|1|5ed|
   3.147 +Blue|Mistform Sliver|Creature|1|lgn|
   3.148 +Blue|Oraxid|Creature|1|nms|
   3.149 +Blue|Phantasmal Terrain|Enchantment|1|5ed|
   3.150 +Blue|Phantasmal Terrain|Enchantment|1|inv|
   3.151 +Blue|Port Inspector|Creature|2|mmq|
   3.152 +Blue|Power Sink|Instant|1|5ed|
   3.153 +Blue|Prodigal Sorcerer|Creature|1|5ed|
   3.154 +Blue|Prohibit|Instant|2|inv|
   3.155 +Blue|Psychic Venom|Enchantment|1|5ed|
   3.156 +Blue|Psychic Venom|Enchantment|2|6ed|
   3.157 +Blue|Sapphire Leech|Creature|1|inv|
   3.158 +Blue|Saprazzan Outrigger|Creature|1|mmq|
   3.159 +Blue|Sea Monster|Creature|1|tmp|
   3.160 +Blue|Segovian Leviathan|Creature|1|5ed|
   3.161 +Blue|Segovian Leviathan|Creature|1|6ed|
   3.162 +Blue|Shadow Rift|Instant|1|tor|
   3.163 +Blue|Sneaky Homunculus|Creature|1|nms|
   3.164 +Blue|Spell Blast|Instant|1|tmp|
   3.165 +Blue|Storm Crow|Creature|1|6ed|
   3.166 +Blue|Stringing Licid|Creature|1|tmp|
   3.167 +Blue|Synapse Sliver|Creature|1|lgn|
   3.168 +Blue|Talas Air Ship|Creature|1|po2|
   3.169 +Blue|Telepathy|Enchantment|1|9ed|
   3.170 +Blue|Tower Drake|Creature|1|inv|
   3.171 +Blue|Updraft|Instant|1|5ed|
   3.172 +Blue|Vizzerdrix|Creature|2|9ed|
   3.173 +Blue|Vodalian Merchant|Creature|1|inv|
   3.174 +Blue|Vodalian Serpent|Creature|1|inv|
   3.175 +Blue|Voidmage Apprentice|Creature|1|lgn|
   3.176 +Blue|Warped Researcher|Creature|1|lgn|
   3.177 +Blue|Welkin Tern|Creature|1|m15|
   3.178 +Blue|Whirlpool Warrior|Creature|1|apc|
   3.179 +Blue|Wind Drake|Creature|1|9ed|
   3.180 +Blue|Worldly Counsel|Instant|1|inv|
   3.181 +Green|Aggressive Urge|Instant|1|inv|
   3.182 +Green|Aurochs|Creature|1|5ed|
   3.183 +Green|Berserk Murlodont|Creature|1|lgn|
   3.184 +Green|Birds of Paradise|Creature|1|6ed|
   3.185 +Green|Blanchwood Armor|Enchantment|1|9ed|
   3.186 +Green|Cat Warriors|Creature|1|6ed|
   3.187 +Green|Cockatrice|Creature|1|5ed|
   3.188 +Green|Craw Wurm|Creature|1|9ed|
   3.189 +Green|Eladamri, Lord of Leaves|Creature|1|tmp|
   3.190 +Green|Elven Cache|Sorcery|1|6ed|
   3.191 +Green|Enormous Baloth|Creature|2|9ed|
   3.192 +Green|Femeref Archers|Creature|1|6ed|
   3.193 +Green|Ferocity|Enchantment|1|mmq|
   3.194 +Green|Forest|Land|29|*|9x5ed,6x6ed,6xinv,8x9ed
   3.195 +Green|Gaea's Balance|Sorcery|1|apc|
   3.196 +Green|Gather Courage|Instant|1|m15|
   3.197 +Green|Giant Growth|Instant|2|6ed|
   3.198 +Green|Glade Gnarr|Creature|2|apc|
   3.199 +Green|Gorilla Chieftain|Creature|1|6ed|
   3.200 +Green|Grizzly Bears|Creature|1|5ed|
   3.201 +Green|Grizzly Bears|Creature|2|9ed|
   3.202 +Green|Gurzigost|Creature|1|tor|
   3.203 +Green|Hickory Woodlot|Land|1|mmq|
   3.204 +Green|Horned Sliver|Creature|1|tmp|
   3.205 +Green|Hungry Mist|Creature|1|5ed|
   3.206 +Green|Kavu Climber|Creature|1|inv|
   3.207 +Green|Krosan Constrictor|Creature|1|tor|
   3.208 +Green|Living Totem|Creature|1|m15|
   3.209 +Green|Llanowar Elite|Creature|1|inv|
   3.210 +Green|Llanowar Vanguard|Creature|1|inv|
   3.211 +Green|Longshot Squad|Creature|1|ktk|
   3.212 +Green|Meandering Towershell|Creature|1|ktk|foil
   3.213 +Green|Naturalize|Instant|1|9ed|
   3.214 +Green|Norwood Ranger|Creature|2|9ed|
   3.215 +Green|Penumbra Bobcat|Creature|1|apc|
   3.216 +Green|Pincer Spider|Creature|1|inv|
   3.217 +Green|Pulse of Llanowar|Enchantment|1|inv|
   3.218 +Green|Quick Sliver|Creature|1|lgn|
   3.219 +Green|Rampant Growth|Sorcery|1|9ed|
   3.220 +Green|Reclamation Sage|Creature|1|m15|
   3.221 +Green|Regeneration|Enchantment|1|5ed|
   3.222 +Green|Regeneration|Enchantment|2|6ed|
   3.223 +Green|Rootbreaker Wurm|Creature|1|tmp|
   3.224 +Green|Runeclaw Bear|Creature|1|m15|
   3.225 +Green|Rushwood Dryad|Creature|1|mmq|
   3.226 +Green|Rushwood Grove|Land|1|mmq|
   3.227 +Green|Rushwood Herbalist|Creature|2|mmq|
   3.228 +Green|Saproling Burst|Enchantment|1|nms|
   3.229 +Green|Satyr Wayfinder|Creature|1|m15|
   3.230 +Green|Savage Punch|Sorcery|1|ktk|
   3.231 +Green|Scaled Wurm|Creature|2|5ed|
   3.232 +Green|Scryb Sprites|Creature|1|5ed|
   3.233 +Green|Shrink|Instant|1|5ed|
   3.234 +Green|Skyshroud Ridgeback|Creature|1|nms|
   3.235 +Green|Skyshroud Sentinel|Creature|1|nms|
   3.236 +Green|Snorting Gahr|Creature|1|mmq|
   3.237 +Green|Spined Wurm|Creature|1|9ed|
   3.238 +Green|Spontaneous Generation|Sorcery|1|mmq|
   3.239 +Green|Stream of Life|Sorcery|1|6ed|
   3.240 +Green|Sylvan Library|Enchantment|1|5ed|
   3.241 +Green|Thicket Basilisk|Creature|1|6ed|
   3.242 +Green|Tiger Claws|Enchantment|1|mmq|
   3.243 +Green|Tranquil Path|Sorcery|1|apc|
   3.244 +Green|Treefolk Healer|Creature|1|inv|
   3.245 +Green|Untamed Wilds|Sorcery|1|6ed|
   3.246 +Green|Verdant Haven|Enchantment|1|m15|
   3.247 +Green|Vigorous Charge|Instant|1|inv|
   3.248 +Green|Wandering Stream|Sorcery|1|inv|
   3.249 +Green|Wanderlust|Enchantment|1|5ed|
   3.250 +Green|Wild Growth|Enchantment|1|5ed|
   3.251 +Green|Winter Blast|Sorcery|1|5ed|
   3.252 +Green|Woodripper|Creature|1|nms|
   3.253 +Green|Yavimaya Wurm|Creature|1|ulg|
   3.254 +Green/Black|Life/Death|Sorcery|1|apc|
   3.255 +Red|Act on Impulse|Sorcery|1|m15|
   3.256 +Red|Aether Flash|Enchantment|1|6ed|
   3.257 +Red|Anaba Shaman|Creature|1|6ed|
   3.258 +Red|Anaba Shaman|Creature|1|9ed|
   3.259 +Red|Battle Rampart|Creature|1|mmq|
   3.260 +Red|Blood Frenzy|Instant|1|tmp|
   3.261 +Red|Bloodfire Dwarf|Creature|2|apc|
   3.262 +Red|Bloodstoke Howler|Creature|1|lgn|
   3.263 +Red|Bring Low|Instant|1|ktk|
   3.264 +Red|Burning Anger|Enchantment|1|m15|
   3.265 +Red|Cave Sense|Enchantment|1|mmq|
   3.266 +Red|Collapsing Borders|Enchantment|1|inv|
   3.267 +Red|Crackling Club|Enchantment|1|tor|
   3.268 +Red|Detonate|Sorcery|1|5ed|
   3.269 +Red|Dwarven Landslide|Sorcery|1|apc|
   3.270 +Red|Dwarven Soldier|Creature|1|5ed|
   3.271 +Red|Dwarven Warriors|Creature|1|5ed|
   3.272 +Red|Enslaved Dwarf|Creature|1|tor|
   3.273 +Red|Firebrand Ranger|Creature|1|inv|
   3.274 +Red|Flame Spirit|Creature|2|6ed|
   3.275 +Red|Flamewave Invoker|Creature|1|lgn|
   3.276 +Red|Flaming Sword|Enchantment|1|mmq|
   3.277 +Red|Generator Servant|Creature|1|m15|
   3.278 +Red|Goblin Dynamo|Creature|1|lgn|
   3.279 +Red|Goblin Elite Infantry|Creature|1|6ed|
   3.280 +Red|Goblin Hero|Creature|1|6ed|
   3.281 +Red|Goblin Raider|Creature|2|9ed|
   3.282 +Red|Goblin Roughrider|Creature|1|m15|
   3.283 +Red|Goblin War Drums|Enchantment|1|5ed|
   3.284 +Red|Goblin Warrens|Enchantment|1|6ed|
   3.285 +Red|Heart Sliver|Creature|1|tmp|
   3.286 +Red|Hill Giant|Creature|2|9ed|
   3.287 +Red|Hill Giant|Creature|1|5ed|
   3.288 +Red|Hooded Kavu|Creature|1|inv|
   3.289 +Red|Hulking Cyclops|Creature|1|6ed|
   3.290 +Red|Ironclaw Orcs|Creature|1|5ed|
   3.291 +Red|Kavu Scout|Creature|1|inv|
   3.292 +Red|Laccolith Grunt|Creature|1|nms|
   3.293 +Red|Laccolith Rig|Enchantment|1|nms|
   3.294 +Red|Lava Axe|Sorcery|2|9ed|
   3.295 +Red|Lightning Blast|Instant|1|6ed|
   3.296 +Red|Maniacal Rage|Enchantment|2|inv|
   3.297 +Red|Mountain|Land|27|*|10x5ed,1x6ed,6xinv,9x9ed,1xktk
   3.298 +Red|Ogre Taskmaster|Creature|1|9ed|
   3.299 +Red|Orcish Oriflamme|Enchantment|1|5ed|
   3.300 +Red|Orgg|Creature|1|5ed|
   3.301 +Red|Petravark|Creature|1|tor|
   3.302 +Red|Pyrotechnics|Sorcery|2|6ed|
   3.303 +Red|Sandstone Needle|Land|1|mmq|
   3.304 +Red|Scarred Puma|Creature|1|inv|
   3.305 +Red|Scorching Lava|Instant|2|inv|
   3.306 +Red|Shadowstorm|Sorcery|1|tmp|
   3.307 +Red|Shatter|Instant|1|6ed|
   3.308 +Red|Shatter|Instant|1|ktk|
   3.309 +Red|Skirk Marauder|Creature|1|lgn|
   3.310 +Red|Slimy Kavu|Creature|1|inv|
   3.311 +Red|Spitting Earth|Sorcery|1|6ed|
   3.312 +Red|Stone Rain|Sorcery|1|9ed|
   3.313 +Red|Tahngarth's Glare|Sorcery|1|apc|
   3.314 +Red|Thundering Giant|Creature|1|m15|
   3.315 +Red|Viashino Warrior|Creature|1|6ed|
   3.316 +Red|Volcanic Hammer|Sorcery|2|9ed|
   3.317 +Red|Wall of Fire|Creature|1|m15|
   3.318 +Red|Zap|Instant|1|apc|
   3.319 +White|Abzan Falconer|Creature|1|ktk|
   3.320 +White|Armageddon|Sorcery|1|5ed|
   3.321 +White|Armored Pegasus|Creature|1|6ed|
   3.322 +White|Avacyn, Guardian Angel|Creature|1|m15|
   3.323 +White|Blessed Wine|Instant|1|5ed|
   3.324 +White|Charm Peddler|Creature|2|mmq|
   3.325 +White|Circle of Protection: Artifacts|Enchantment|1|5ed|
   3.326 +White|Circle of Protection: Black|Enchantment|1|5ed|
   3.327 +White|Circle of Protection: Blue|Enchantment|1|6ed|
   3.328 +White|Circle of Protection: Green|Enchantment|1|6ed|
   3.329 +White|Circle of Protection: White|Enchantment|1|5ed|
   3.330 +White|Congregate|Instant|1|m15|
   3.331 +White|D'Avenant Archer|Creature|2|6ed|
   3.332 +White|Daru Mender|Creature|1|lgn|
   3.333 +White|Daru Sanctifier|Creature|1|lgn|
   3.334 +White|Daru Stinger|Creature|1|lgn|
   3.335 +White|Death Ward|Instant|1|5ed|
   3.336 +White|Devout Witness|Creature|1|mmq|
   3.337 +White|Disenchant|Instant|1|5ed|
   3.338 +White|Dismantling Blow|Instant|1|inv|
   3.339 +White|Eager Cadet|Creature|1|9ed|
   3.340 +White|Erase|Instant|1|ktk|
   3.341 +White|Fanatical Devotion|Enchantment|1|nms|
   3.342 +White|Glimmering Angel|Creature|1|inv|
   3.343 +White|Glory Seeker|Creature|4|9ed|
   3.344 +White|Holy Day|Instant|1|9ed|
   3.345 +White|Honor Guard|Creature|1|9ed|
   3.346 +White|Icatian Town|Sorcery|1|5ed|
   3.347 +White|Infantry Veteran|Creature|1|6ed|
   3.348 +White|Last Breath|Instant|1|mmq|
   3.349 +White|Liberate|Instant|1|inv|
   3.350 +White|Light of Day|Enchantment|1|6ed|
   3.351 +White|Manacles of Decay|Enchantment|1|apc|
   3.352 +White|Meditation Puzzle|Instant|1|m15|
   3.353 +White|Moment of Silence|Instant|1|mmq|
   3.354 +White|Mystic Familiar|Creature|1|tor|
   3.355 +White|Nightwind Glider|Creature|1|mmq|
   3.356 +White|Off Balance|Instant|1|nms|
   3.357 +White|Oppressive Rays|Enchantment|1|m15|
   3.358 +White|Order of the White Shield|Creature|1|5ed|
   3.359 +White|Orim's Touch|Instant|1|inv|
   3.360 +White|Pearled Unicorn|Creature|1|5ed|
   3.361 +White|Pikemen|Creature|1|5ed|
   3.362 +White|Plains|Land|23|*|8x5ed,6xinv,9x9ed
   3.363 +White|Prison Barricade|Creature|1|inv|
   3.364 +White|Sacred Nectar|Sorcery|2|9ed|
   3.365 +White|Samite Healer|Creature|1|5ed|
   3.366 +White|Samite Healer|Creature|1|6ed|
   3.367 +White|Serra Angel|Creature|1|9ed|foil
   3.368 +White|Shield of Duty and Reason|Enchantment|2|apc|
   3.369 +White|Siegecraft|Enchantment|1|ktk|
   3.370 +White|Strenght of Isolation|Enchantment|1|tor|
   3.371 +White|Strength of Unity|Enchantment|1|inv|
   3.372 +White|Thermal Glider|Creature|1|mmq|
   3.373 +White|Tireless Missionaries|Creature|1|m15|
   3.374 +White|Trap Runner|Creature|2|mmq|
   3.375 +White|Triplicate Spirits|Sorcery|1|m15|
   3.376 +White|Tundra Wolves|Creature|2|5ed|
   3.377 +White|Vengeance|Sorcery|2|9ed|
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/editions.cfg	Sun Nov 02 11:07:45 2014 +0200
     4.3 @@ -0,0 +1,101 @@
     4.4 +LEA|Limited Edition Alpha
     4.5 +LEB|Limited Edition Beta
     4.6 +2ED|Unlimited
     4.7 +ARN|Arabian Nights
     4.8 +ATQ|Antiquities
     4.9 +3ED|Revised
    4.10 +LEG|Legends
    4.11 +DRK|The Dark
    4.12 +FEM|Fallen Empires
    4.13 +4ED|4th Edition
    4.14 +ICE|Ice Age
    4.15 +CHR|Chronicles
    4.16 +HML|Homelands
    4.17 +ALL|Alliances
    4.18 +MIR|Mirage
    4.19 +VIS|Visions
    4.20 +5ED|5th Edition
    4.21 +POR|Portal
    4.22 +WTH|Weatherlight
    4.23 +TMP|Tempest
    4.24 +STH|Stronghold
    4.25 +PO2|Portal The Second Age
    4.26 +EXO|Exodus
    4.27 +USG|Urza's Saga
    4.28 +ULG|Urza's Legacy
    4.29 +6ED|6th Edition
    4.30 +UDS|Urza's Destiny
    4.31 +S99|Starter 1999
    4.32 +MMQ|Mercadian Masques
    4.33 +NMS|Nemesis
    4.34 +PCY|Prophecy
    4.35 +INV|Invasion
    4.36 +BTD|Beatdown
    4.37 +PLS|Planeshift
    4.38 +7ED|7th Edition
    4.39 +APC|Apocalypse
    4.40 +ODY|Odyssey
    4.41 +DKM|Deckmasters 2001
    4.42 +TOR|Torment
    4.43 +JUD|Judgment
    4.44 +ONS|Onslaught
    4.45 +LGN|Legions
    4.46 +SCG|Scourge
    4.47 +8ED|8th Edition
    4.48 +MRD|Mirrodin
    4.49 +DST|Darksteel
    4.50 +5DN|Fifth Dawn
    4.51 +CHK|Champions of Kamigawa
    4.52 +BOK|Betrayers of Kamigawa
    4.53 +SOK|Saviors of Kamigawa
    4.54 +9ED|9th Edition
    4.55 +RAV|Ravnica: City of Guilds
    4.56 +GPT|Guildpact
    4.57 +DIS|Dissension
    4.58 +CLD|Coldsnap
    4.59 +TSP|Time Spiral
    4.60 +PLC|Planar Chaos
    4.61 +FST|Future Sight
    4.62 +10E|10th Edition
    4.63 +LRW|Lorwyn
    4.64 +MOR|Morningtide
    4.65 +SHM|Shadowmoor
    4.66 +EVE|Eventide
    4.67 +ALA|Shards of Alara
    4.68 +CON|Conflux
    4.69 +DDC|Duel Decks: Divine vs. Demonic
    4.70 +ARB|Alara Reborn
    4.71 +M10|Magic 2010
    4.72 +ZEN|Zendikar
    4.73 +H09|Premium Deck Series: Slivers
    4.74 +WWK|Worldwake
    4.75 +DDE|Duel Decks: Phyrexia vs. the Coalition
    4.76 +ROE|Rise of the Eldrazi
    4.77 +M11|Magic 2011
    4.78 +DDF|Duel Decks: Elspeth vs. Tezzeret
    4.79 +SOM|Scars of Mirrodin
    4.80 +MBS|Mirrodin Besieged
    4.81 +DDG|Duel Decks: Knights vs. Dragons
    4.82 +NPH|New Phyrexia
    4.83 +CMD|Commander
    4.84 +M12|Magic 2012
    4.85 +DDH|Duel Decks: Ajani vs. Nicol Bolas
    4.86 +ISD|Innistrad
    4.87 +DKA|Dark Ascension
    4.88 +DDI|Duel Decks: Venser vs. Koth
    4.89 +AVR|Avacyn Restored
    4.90 +M13|Magic 2013
    4.91 +DDJ|Duel Decks: Izzet Vs. Golgari
    4.92 +RTR|Return to Ravnica
    4.93 +GTC|Gatecrash
    4.94 +DDK|Duel Decks: Sorin vs. Tibalt
    4.95 +DGM|Dragon's Maze
    4.96 +MMA|Modern Masters
    4.97 +M14|Magic 2014
    4.98 +THS|Theros
    4.99 +C13|Commander 2013
   4.100 +BNG|Born of the Gods
   4.101 +JOU|Journey into Nyx
   4.102 +CNS|Conspiracy
   4.103 +M15|Magic 2015
   4.104 +KTK|Khans of Tarkir
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/mtg.c	Sun Nov 02 11:07:45 2014 +0200
     5.3 @@ -0,0 +1,290 @@
     5.4 +#include <stdio.h>
     5.5 +#include <stdlib.h>
     5.6 +#include <string.h>
     5.7 +#include <ctype.h>
     5.8 +#include <errno.h>
     5.9 +#include "rbtree.h"
    5.10 +#include "mtg.h"
    5.11 +
    5.12 +#define ED_FNAME	"editions.cfg"
    5.13 +
    5.14 +static int load_editions(void);
    5.15 +static unsigned int parse_color(const char *colstr, const char *notes);
    5.16 +static int strcmp_lower(const char *a, const char *b);
    5.17 +static void rbdel(struct rbnode *node, void *cls);
    5.18 +
    5.19 +static struct {
    5.20 +	enum mtg_card_type type;
    5.21 +	const char *name;
    5.22 +} type_names[] = {
    5.23 +	{MTG_TYPE_LAND, "Land"},
    5.24 +	{MTG_TYPE_CREATURE, "Creature"},
    5.25 +	{MTG_TYPE_SORCERY, "Sorcery"},
    5.26 +	{MTG_TYPE_INSTANT, "Instant"},
    5.27 +	{MTG_TYPE_ENCHANTMENT, "Enchantment"},
    5.28 +	{MTG_TYPE_ARTIFACT, "Artifact"},
    5.29 +	{MTG_TYPE_PLANESWALKER, "Planeswalker"},
    5.30 +	{MTG_TYPE_UNKNOWN, 0}
    5.31 +};
    5.32 +
    5.33 +static struct rbtree *cards;
    5.34 +static struct rbtree *editions;
    5.35 +
    5.36 +
    5.37 +int mtg_init(void)
    5.38 +{
    5.39 +	if(cards || editions) {
    5.40 +		fprintf(stderr, "mtg already initialized\n");
    5.41 +		return -1;
    5.42 +	}
    5.43 +
    5.44 +	if(!(cards = rb_create((rb_cmp_func_t)strcmp_lower))) {
    5.45 +		goto err;
    5.46 +	}
    5.47 +	rb_set_delete_func(cards, rbdel, 0);
    5.48 +
    5.49 +	if(!(editions = rb_create((rb_cmp_func_t)strcmp_lower))) {
    5.50 +		goto err;
    5.51 +	}
    5.52 +	rb_set_delete_func(editions, rbdel, 0);
    5.53 +
    5.54 +	if(load_editions() == -1) {
    5.55 +		goto err;
    5.56 +	}
    5.57 +	return 0;
    5.58 +
    5.59 +err:
    5.60 +	if(cards) rb_destroy(cards);
    5.61 +	if(editions) rb_destroy(editions);
    5.62 +	return -1;
    5.63 +}
    5.64 +
    5.65 +void mtg_destroy(void)
    5.66 +{
    5.67 +	rb_free(cards);
    5.68 +	rb_free(editions);
    5.69 +	cards = editions = 0;
    5.70 +}
    5.71 +
    5.72 +int mtg_load_cards(const char *fname)
    5.73 +{
    5.74 +	int i;
    5.75 +	FILE *fp;
    5.76 +	char buf[512];
    5.77 +
    5.78 +	if(!(fp = fopen(fname, "r"))) {
    5.79 +		fprintf(stderr, "failed to open magic list: %s: %s\n", fname, strerror(errno));
    5.80 +		return -1;
    5.81 +	}
    5.82 +
    5.83 +	while(fgets(buf, sizeof buf, fp)) {
    5.84 +		struct mtg_card *card;
    5.85 +		char *field[6];
    5.86 +
    5.87 +		for(i=0; i<6; i++) {
    5.88 +			field[i] = strtok(i ? 0 : buf, "|\n\r\t\v;");
    5.89 +		}
    5.90 +
    5.91 +		if(!(card = malloc(sizeof *card))) {
    5.92 +			continue;
    5.93 +		}
    5.94 +		if(!field[1] || !(card->name = strdup(field[1]))) {
    5.95 +			free(card);
    5.96 +			continue;
    5.97 +		}
    5.98 +		card->color = parse_color(field[0], field[5]);
    5.99 +		card->type = mtg_str_type(field[2]);
   5.100 +		card->edition = mtg_edition(field[4]);
   5.101 +		card->count = atoi(field[3]);
   5.102 +
   5.103 +		rb_insert(cards, card->name, card);
   5.104 +	}
   5.105 +
   5.106 +	fclose(fp);
   5.107 +	return 0;
   5.108 +}
   5.109 +
   5.110 +void mtg_iter_begin(void)
   5.111 +{
   5.112 +	rb_begin(cards);
   5.113 +}
   5.114 +
   5.115 +const struct mtg_card *mtg_iter_next(void)
   5.116 +{
   5.117 +	struct rbnode *node = rb_next(cards);
   5.118 +	return node ? rb_node_data(node) : 0;
   5.119 +}
   5.120 +
   5.121 +#define ADDCOL(x)	\
   5.122 +	do { \
   5.123 +		if(*str) { \
   5.124 +			strcat(str, "/"); \
   5.125 +		} \
   5.126 +		strcat(str, x); \
   5.127 +	} while(0)
   5.128 +
   5.129 +const char *mtg_color_str(unsigned int color)
   5.130 +{
   5.131 +	static char str[128];
   5.132 +	str[0] = 0;
   5.133 +
   5.134 +	if(color == MTG_COL_MULTI) {
   5.135 +		return "multicolor";
   5.136 +	}
   5.137 +
   5.138 +	if(color & MTG_COL_RED) {
   5.139 +		ADDCOL("red");
   5.140 +	}
   5.141 +	if(color & MTG_COL_GREEN) {
   5.142 +		ADDCOL("green");
   5.143 +	}
   5.144 +	if(color & MTG_COL_BLUE) {
   5.145 +		ADDCOL("blue");
   5.146 +	}
   5.147 +	if(color & MTG_COL_BLACK) {
   5.148 +		ADDCOL("black");
   5.149 +	}
   5.150 +	if(color & MTG_COL_WHITE) {
   5.151 +		ADDCOL("white");
   5.152 +	}
   5.153 +	if(color & MTG_COL_ARTIFACT) {
   5.154 +		ADDCOL("artifact");
   5.155 +	}
   5.156 +	return str[0] ? str : "colorless";
   5.157 +}
   5.158 +
   5.159 +const char *mtg_type_str(enum mtg_card_type type)
   5.160 +{
   5.161 +	int i;
   5.162 +	for(i=0; type_names[i].name; i++) {
   5.163 +		if(type_names[i].type == type) {
   5.164 +			return type_names[i].name;
   5.165 +		}
   5.166 +	}
   5.167 +	return MTG_TYPE_UNKNOWN;
   5.168 +}
   5.169 +
   5.170 +enum mtg_card_type mtg_str_type(const char *s)
   5.171 +{
   5.172 +	int i;
   5.173 +	for(i=0; type_names[i].name; i++) {
   5.174 +		if(strcmp_lower(type_names[i].name, s) == 0) {
   5.175 +			return type_names[i].type;
   5.176 +		}
   5.177 +	}
   5.178 +	return MTG_TYPE_UNKNOWN;
   5.179 +}
   5.180 +
   5.181 +const char *mtg_edition(const char *edcode)
   5.182 +{
   5.183 +	struct rbnode *node = rb_find(editions, (void*)edcode);
   5.184 +	if(!node) {
   5.185 +		return "unknown";
   5.186 +	}
   5.187 +	return rb_node_data(node);
   5.188 +}
   5.189 +
   5.190 +int mtg_is_multicolor(unsigned int color)
   5.191 +{
   5.192 +	int i, bits = 0;
   5.193 +
   5.194 +	for(i=0; i<16; i++) {
   5.195 +		if(color & 1) ++bits;
   5.196 +		color >>= 1;
   5.197 +	}
   5.198 +	return bits > 1;
   5.199 +}
   5.200 +
   5.201 +static void dbgprint(struct rbnode *node, void *cls)
   5.202 +{
   5.203 +	fprintf(stderr, "%s\n", (char*)rb_node_key(node));
   5.204 +}
   5.205 +
   5.206 +static int load_editions(void)
   5.207 +{
   5.208 +	FILE *fp;
   5.209 +	char buf[128];
   5.210 +
   5.211 +	if(!(fp = fopen(ED_FNAME, "r"))) {
   5.212 +		perror("failed to open editions config file: " ED_FNAME);
   5.213 +		return -1;
   5.214 +	}
   5.215 +
   5.216 +	while(fgets(buf, sizeof buf, fp)) {
   5.217 +		char *code, *name;
   5.218 +
   5.219 +		code = strtok(buf, "|\n\r");
   5.220 +		if(!code) continue;
   5.221 +
   5.222 +		name = strtok(0, "|\n\r");
   5.223 +		if(!name) continue;
   5.224 +
   5.225 +		rb_insert(editions, strdup(code), strdup(name));
   5.226 +	}
   5.227 +
   5.228 +	rb_foreach(editions, dbgprint, 0);
   5.229 +
   5.230 +	fclose(fp);
   5.231 +	return 0;
   5.232 +}
   5.233 +
   5.234 +static unsigned int parse_multicolor(const char *str)
   5.235 +{
   5.236 +	int i;
   5.237 +	unsigned int mask = 0;
   5.238 +
   5.239 +	char *cstr = alloca(strlen(str) + 1);
   5.240 +	for(i=0; str[i]; i++) {
   5.241 +		cstr[i] = tolower(str[i]);
   5.242 +	}
   5.243 +	cstr[i] = 0;
   5.244 +
   5.245 +	if(strstr(cstr, "red")) mask |= MTG_COL_RED;
   5.246 +	if(strstr(cstr, "green")) mask |= MTG_COL_GREEN;
   5.247 +	if(strstr(cstr, "blue")) mask |= MTG_COL_BLUE;
   5.248 +	if(strstr(cstr, "black")) mask |= MTG_COL_BLACK;
   5.249 +	if(strstr(cstr, "white")) mask |= MTG_COL_WHITE;
   5.250 +	if(strstr(cstr, "artifact")) mask |= MTG_COL_ARTIFACT;
   5.251 +
   5.252 +	return mask;
   5.253 +}
   5.254 +
   5.255 +static unsigned int parse_color(const char *colstr, const char *notes)
   5.256 +{
   5.257 +	int i;
   5.258 +	unsigned int res = 0;
   5.259 +	char *cstr = alloca(strlen(colstr) + 1);
   5.260 +	for(i=0; colstr[i]; i++) {
   5.261 +		cstr[i] = tolower(colstr[i]);
   5.262 +	}
   5.263 +	cstr[i] = 0;
   5.264 +
   5.265 +	if((res = parse_multicolor(colstr))) {
   5.266 +		return res;
   5.267 +	}
   5.268 +
   5.269 +	if(strcmp(cstr, "*") == 0) {
   5.270 +		if((res = parse_multicolor(notes))) {
   5.271 +			return res;
   5.272 +		}
   5.273 +		return MTG_COL_MULTI;
   5.274 +	}
   5.275 +
   5.276 +	return MTG_COL_NONE;
   5.277 +}
   5.278 +
   5.279 +static int strcmp_lower(const char *a, const char *b)
   5.280 +{
   5.281 +	return strcasecmp(a, b);
   5.282 +	while(*a && tolower(*a) == tolower(*b)) {
   5.283 +		++a;
   5.284 +		++b;
   5.285 +	}
   5.286 +	return tolower(*a) - tolower(*b);
   5.287 +}
   5.288 +
   5.289 +static void rbdel(struct rbnode *node, void *cls)
   5.290 +{
   5.291 +	free(rb_node_key(node));
   5.292 +	free(rb_node_data(node));
   5.293 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/mtg.h	Sun Nov 02 11:07:45 2014 +0200
     6.3 @@ -0,0 +1,52 @@
     6.4 +#ifndef MTG_H_
     6.5 +#define MTG_H_
     6.6 +
     6.7 +#define MTG_COL_NONE		0
     6.8 +#define MTG_COL_RED			1
     6.9 +#define MTG_COL_GREEN		2
    6.10 +#define MTG_COL_BLUE		4
    6.11 +#define MTG_COL_BLACK		8
    6.12 +#define MTG_COL_WHITE		16
    6.13 +#define MTG_COL_ARTIFACT	32
    6.14 +#define MTG_COL_MULTI		0xff
    6.15 +
    6.16 +enum mtg_card_type {
    6.17 +	MTG_TYPE_UNKNOWN,
    6.18 +
    6.19 +	MTG_TYPE_LAND,
    6.20 +	MTG_TYPE_CREATURE,
    6.21 +	MTG_TYPE_SORCERY,
    6.22 +	MTG_TYPE_INSTANT,
    6.23 +	MTG_TYPE_ENCHANTMENT,
    6.24 +	MTG_TYPE_ARTIFACT,
    6.25 +	MTG_TYPE_PLANESWALKER
    6.26 +};
    6.27 +
    6.28 +
    6.29 +struct mtg_card {
    6.30 +	char *name;
    6.31 +	unsigned int color;
    6.32 +	enum mtg_card_type type;
    6.33 +	const char *edition;
    6.34 +	int count;
    6.35 +};
    6.36 +
    6.37 +int mtg_init(void);
    6.38 +void mtg_destroy(void);
    6.39 +
    6.40 +int mtg_load_cards(const char *fname);
    6.41 +
    6.42 +void mtg_iter_begin(void);
    6.43 +const struct mtg_card *mtg_iter_next(void);
    6.44 +
    6.45 +const char *mtg_color_str(unsigned int color);
    6.46 +
    6.47 +const char *mtg_type_str(enum mtg_card_type type);
    6.48 +enum mtg_card_type mtg_str_type(const char *s);
    6.49 +
    6.50 +const char *mtg_edition(const char *edcode);
    6.51 +
    6.52 +int mtg_is_multicolor(unsigned int color);
    6.53 +
    6.54 +
    6.55 +#endif	/* MTG_H_ */
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/mtglist.c	Sun Nov 02 11:07:45 2014 +0200
     7.3 @@ -0,0 +1,40 @@
     7.4 +#include <stdio.h>
     7.5 +#include <stdlib.h>
     7.6 +#include <string.h>
     7.7 +#include "mtg.h"
     7.8 +
     7.9 +int main(int argc, char **argv)
    7.10 +{
    7.11 +	const struct mtg_card *card;
    7.12 +	const char *fname = "cardlist";
    7.13 +	int ncards;
    7.14 +
    7.15 +	if(argv[1]) fname = argv[1];
    7.16 +
    7.17 +	if(mtg_init() == -1) {
    7.18 +		return 1;
    7.19 +	}
    7.20 +
    7.21 +	if(mtg_load_cards(fname) == -1) {
    7.22 +		mtg_destroy();
    7.23 +		return 1;
    7.24 +	}
    7.25 +
    7.26 +	ncards = 0;
    7.27 +
    7.28 +	mtg_iter_begin();
    7.29 +	while((card = mtg_iter_next())) {
    7.30 +		printf("%3d  ", card->count);
    7.31 +		printf("%-11s ", mtg_color_str(card->color));
    7.32 +		printf("%-32s ", card->name);
    7.33 +		printf("%-12s ", mtg_type_str(card->type));
    7.34 +		printf("%s\n", card->edition);
    7.35 +
    7.36 +		ncards += card->count;
    7.37 +	}
    7.38 +
    7.39 +	printf("Total cards: %d\n", ncards);
    7.40 +
    7.41 +	mtg_destroy();
    7.42 +	return 0;
    7.43 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/rbtree.c	Sun Nov 02 11:07:45 2014 +0200
     8.3 @@ -0,0 +1,501 @@
     8.4 +/*
     8.5 +rbtree - simple balanced binary search tree (red-black tree) library.
     8.6 +Copyright (C) 2011-2014  John Tsiombikas <nuclear@member.fsf.org>
     8.7 +
     8.8 +rbtree is free software, feel free to use, modify, and redistribute it, under
     8.9 +the terms of the 3-clause BSD license. See COPYING for details.
    8.10 + */
    8.11 +#include <stdio.h>
    8.12 +#include <stdlib.h>
    8.13 +#include <stdint.h>
    8.14 +#include <string.h>
    8.15 +#include "rbtree.h"
    8.16 +
    8.17 +#define INT2PTR(x)	((void*)(intptr_t)(x))
    8.18 +#define PTR2INT(x)	((int)(intptr_t)(x))
    8.19 +
    8.20 +struct rbtree {
    8.21 +	struct rbnode *root;
    8.22 +
    8.23 +	rb_alloc_func_t alloc;
    8.24 +	rb_free_func_t free;
    8.25 +
    8.26 +	rb_cmp_func_t cmp;
    8.27 +	rb_del_func_t del;
    8.28 +	void *del_cls;
    8.29 +
    8.30 +	struct rbnode *rstack, *iter;
    8.31 +};
    8.32 +
    8.33 +static int cmpaddr(const void *ap, const void *bp);
    8.34 +static int cmpint(const void *ap, const void *bp);
    8.35 +
    8.36 +static int count_nodes(struct rbnode *node);
    8.37 +static void del_tree(struct rbnode *node, void (*delfunc)(struct rbnode*, void*), void *cls);
    8.38 +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data);
    8.39 +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key);
    8.40 +/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key);*/
    8.41 +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls);
    8.42 +
    8.43 +struct rbtree *rb_create(rb_cmp_func_t cmp_func)
    8.44 +{
    8.45 +	struct rbtree *rb;
    8.46 +
    8.47 +	if(!(rb = malloc(sizeof *rb))) {
    8.48 +		return 0;
    8.49 +	}
    8.50 +	if(rb_init(rb, cmp_func) == -1) {
    8.51 +		free(rb);
    8.52 +		return 0;
    8.53 +	}
    8.54 +	return rb;
    8.55 +}
    8.56 +
    8.57 +void rb_free(struct rbtree *rb)
    8.58 +{
    8.59 +	rb_destroy(rb);
    8.60 +	free(rb);
    8.61 +}
    8.62 +
    8.63 +
    8.64 +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func)
    8.65 +{
    8.66 +	memset(rb, 0, sizeof *rb);
    8.67 +
    8.68 +	if(!cmp_func) {
    8.69 +		rb->cmp = cmpaddr;
    8.70 +	} else if(cmp_func == RB_KEY_INT) {
    8.71 +		rb->cmp = cmpint;
    8.72 +	} else if(cmp_func == RB_KEY_STRING) {
    8.73 +		rb->cmp = (rb_cmp_func_t)strcmp;
    8.74 +	} else {
    8.75 +		rb->cmp = cmp_func;
    8.76 +	}
    8.77 +
    8.78 +	rb->alloc = malloc;
    8.79 +	rb->free = free;
    8.80 +	return 0;
    8.81 +}
    8.82 +
    8.83 +void rb_destroy(struct rbtree *rb)
    8.84 +{
    8.85 +	del_tree(rb->root, rb->del, rb->del_cls);
    8.86 +}
    8.87 +
    8.88 +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free)
    8.89 +{
    8.90 +	rb->alloc = alloc;
    8.91 +	rb->free = free;
    8.92 +}
    8.93 +
    8.94 +
    8.95 +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func)
    8.96 +{
    8.97 +	rb->cmp = func;
    8.98 +}
    8.99 +
   8.100 +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls)
   8.101 +{
   8.102 +	rb->del = func;
   8.103 +	rb->del_cls = cls;
   8.104 +}
   8.105 +
   8.106 +
   8.107 +void rb_clear(struct rbtree *rb)
   8.108 +{
   8.109 +	del_tree(rb->root, rb->del, rb->del_cls);
   8.110 +	rb->root = 0;
   8.111 +}
   8.112 +
   8.113 +int rb_copy(struct rbtree *dest, struct rbtree *src)
   8.114 +{
   8.115 +	struct rbnode *node;
   8.116 +
   8.117 +	rb_clear(dest);
   8.118 +	rb_begin(src);
   8.119 +	while((node = rb_next(src))) {
   8.120 +		if(rb_insert(dest, node->key, node->data) == -1) {
   8.121 +			return -1;
   8.122 +		}
   8.123 +	}
   8.124 +	return 0;
   8.125 +}
   8.126 +
   8.127 +int rb_size(struct rbtree *rb)
   8.128 +{
   8.129 +	return count_nodes(rb->root);
   8.130 +}
   8.131 +
   8.132 +int rb_insert(struct rbtree *rb, void *key, void *data)
   8.133 +{
   8.134 +	rb->root = insert(rb, rb->root, key, data);
   8.135 +	rb->root->red = 0;
   8.136 +	return 0;
   8.137 +}
   8.138 +
   8.139 +int rb_inserti(struct rbtree *rb, int key, void *data)
   8.140 +{
   8.141 +	rb->root = insert(rb, rb->root, INT2PTR(key), data);
   8.142 +	rb->root->red = 0;
   8.143 +	return 0;
   8.144 +}
   8.145 +
   8.146 +
   8.147 +int rb_delete(struct rbtree *rb, void *key)
   8.148 +{
   8.149 +	rb->root = delete(rb, rb->root, key);
   8.150 +	rb->root->red = 0;
   8.151 +	return 0;
   8.152 +}
   8.153 +
   8.154 +int rb_deletei(struct rbtree *rb, int key)
   8.155 +{
   8.156 +	rb->root = delete(rb, rb->root, INT2PTR(key));
   8.157 +	rb->root->red = 0;
   8.158 +	return 0;
   8.159 +}
   8.160 +
   8.161 +
   8.162 +struct rbnode *rb_find(struct rbtree *rb, void *key)
   8.163 +{
   8.164 +	struct rbnode *node = rb->root;
   8.165 +
   8.166 +	while(node) {
   8.167 +		int cmp = rb->cmp(key, node->key);
   8.168 +		if(cmp == 0) {
   8.169 +			return node;
   8.170 +		}
   8.171 +		node = cmp < 0 ? node->left : node->right;
   8.172 +	}
   8.173 +	return 0;
   8.174 +}
   8.175 +
   8.176 +struct rbnode *rb_findi(struct rbtree *rb, int key)
   8.177 +{
   8.178 +	return rb_find(rb, INT2PTR(key));
   8.179 +}
   8.180 +
   8.181 +
   8.182 +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls)
   8.183 +{
   8.184 +	traverse(rb->root, func, cls);
   8.185 +}
   8.186 +
   8.187 +
   8.188 +struct rbnode *rb_root(struct rbtree *rb)
   8.189 +{
   8.190 +	return rb->root;
   8.191 +}
   8.192 +
   8.193 +void rb_begin(struct rbtree *rb)
   8.194 +{
   8.195 +	rb->rstack = 0;
   8.196 +	rb->iter = rb->root;
   8.197 +}
   8.198 +
   8.199 +#define push(sp, x)		((x)->next = (sp), (sp) = (x))
   8.200 +#define pop(sp)			((sp) = (sp)->next)
   8.201 +#define top(sp)			(sp)
   8.202 +
   8.203 +struct rbnode *rb_next(struct rbtree *rb)
   8.204 +{
   8.205 +	struct rbnode *res = 0;
   8.206 +
   8.207 +	while(rb->rstack || rb->iter) {
   8.208 +		if(rb->iter) {
   8.209 +			push(rb->rstack, rb->iter);
   8.210 +			rb->iter = rb->iter->left;
   8.211 +		} else {
   8.212 +			rb->iter = top(rb->rstack);
   8.213 +			pop(rb->rstack);
   8.214 +			res = rb->iter;
   8.215 +			rb->iter = rb->iter->right;
   8.216 +			break;
   8.217 +		}
   8.218 +	}
   8.219 +	return res;
   8.220 +}
   8.221 +
   8.222 +void *rb_node_key(struct rbnode *node)
   8.223 +{
   8.224 +	return node ? node->key : 0;
   8.225 +}
   8.226 +
   8.227 +int rb_node_keyi(struct rbnode *node)
   8.228 +{
   8.229 +	return node ? PTR2INT(node->key) : 0;
   8.230 +}
   8.231 +
   8.232 +void *rb_node_data(struct rbnode *node)
   8.233 +{
   8.234 +	return node ? node->data : 0;
   8.235 +}
   8.236 +
   8.237 +static int cmpaddr(const void *ap, const void *bp)
   8.238 +{
   8.239 +	return ap < bp ? -1 : (ap > bp ? 1 : 0);
   8.240 +}
   8.241 +
   8.242 +static int cmpint(const void *ap, const void *bp)
   8.243 +{
   8.244 +	return PTR2INT(ap) - PTR2INT(bp);
   8.245 +}
   8.246 +
   8.247 +
   8.248 +/* ---- left-leaning 2-3 red-black implementation ---- */
   8.249 +
   8.250 +/* helper prototypes */
   8.251 +static int is_red(struct rbnode *tree);
   8.252 +static void color_flip(struct rbnode *tree);
   8.253 +static struct rbnode *rot_left(struct rbnode *a);
   8.254 +static struct rbnode *rot_right(struct rbnode *a);
   8.255 +static struct rbnode *find_min(struct rbnode *tree);
   8.256 +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree);
   8.257 +/*static struct rbnode *move_red_right(struct rbnode *tree);*/
   8.258 +static struct rbnode *move_red_left(struct rbnode *tree);
   8.259 +static struct rbnode *fix_up(struct rbnode *tree);
   8.260 +
   8.261 +static int count_nodes(struct rbnode *node)
   8.262 +{
   8.263 +	if(!node)
   8.264 +		return 0;
   8.265 +
   8.266 +	return 1 + count_nodes(node->left) + count_nodes(node->right);
   8.267 +}
   8.268 +
   8.269 +static void del_tree(struct rbnode *node, rb_del_func_t delfunc, void *cls)
   8.270 +{
   8.271 +	if(!node)
   8.272 +		return;
   8.273 +
   8.274 +	del_tree(node->left, delfunc, cls);
   8.275 +	del_tree(node->right, delfunc, cls);
   8.276 +
   8.277 +	if(delfunc) {
   8.278 +		delfunc(node, cls);
   8.279 +	}
   8.280 +	free(node);
   8.281 +}
   8.282 +
   8.283 +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data)
   8.284 +{
   8.285 +	int cmp;
   8.286 +
   8.287 +	if(!tree) {
   8.288 +		struct rbnode *node = rb->alloc(sizeof *node);
   8.289 +		node->red = 1;
   8.290 +		node->key = key;
   8.291 +		node->data = data;
   8.292 +		node->left = node->right = 0;
   8.293 +		return node;
   8.294 +	}
   8.295 +
   8.296 +	cmp = rb->cmp(key, tree->key);
   8.297 +
   8.298 +	if(cmp < 0) {
   8.299 +		tree->left = insert(rb, tree->left, key, data);
   8.300 +	} else if(cmp > 0) {
   8.301 +		tree->right = insert(rb, tree->right, key, data);
   8.302 +	} else {
   8.303 +		tree->data = data;
   8.304 +	}
   8.305 +
   8.306 +	/* fix right-leaning reds */
   8.307 +	if(is_red(tree->right)) {
   8.308 +		tree = rot_left(tree);
   8.309 +	}
   8.310 +	/* fix two reds in a row */
   8.311 +	if(is_red(tree->left) && is_red(tree->left->left)) {
   8.312 +		tree = rot_right(tree);
   8.313 +	}
   8.314 +
   8.315 +	/* if 4-node, split it by color inversion */
   8.316 +	if(is_red(tree->left) && is_red(tree->right)) {
   8.317 +		color_flip(tree);
   8.318 +	}
   8.319 +
   8.320 +	return tree;
   8.321 +}
   8.322 +
   8.323 +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key)
   8.324 +{
   8.325 +	int cmp;
   8.326 +
   8.327 +	if(!tree) {
   8.328 +		return 0;
   8.329 +	}
   8.330 +
   8.331 +	cmp = rb->cmp(key, tree->key);
   8.332 +
   8.333 +	if(cmp < 0) {
   8.334 +		if(!is_red(tree->left) && !is_red(tree->left->left)) {
   8.335 +			tree = move_red_left(tree);
   8.336 +		}
   8.337 +		tree->left = delete(rb, tree->left, key);
   8.338 +	} else {
   8.339 +		/* need reds on the right */
   8.340 +		if(is_red(tree->left)) {
   8.341 +			tree = rot_right(tree);
   8.342 +		}
   8.343 +
   8.344 +		/* found it at the bottom (XXX what certifies left is null?) */
   8.345 +		if(cmp == 0 && !tree->right) {
   8.346 +			if(rb->del) {
   8.347 +				rb->del(tree, rb->del_cls);
   8.348 +			}
   8.349 +			rb->free(tree);
   8.350 +			return 0;
   8.351 +		}
   8.352 +
   8.353 +		if(!is_red(tree->right) && !is_red(tree->right->left)) {
   8.354 +			tree = move_red_left(tree);
   8.355 +		}
   8.356 +
   8.357 +		if(key == tree->key) {
   8.358 +			struct rbnode *rmin = find_min(tree->right);
   8.359 +			tree->key = rmin->key;
   8.360 +			tree->data = rmin->data;
   8.361 +			tree->right = del_min(rb, tree->right);
   8.362 +		} else {
   8.363 +			tree->right = delete(rb, tree->right, key);
   8.364 +		}
   8.365 +	}
   8.366 +
   8.367 +	return fix_up(tree);
   8.368 +}
   8.369 +
   8.370 +/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key)
   8.371 +{
   8.372 +	int cmp;
   8.373 +
   8.374 +	if(!node)
   8.375 +		return 0;
   8.376 +
   8.377 +	if((cmp = rb->cmp(key, node->key)) == 0) {
   8.378 +		return node;
   8.379 +	}
   8.380 +	return find(rb, cmp < 0 ? node->left : node->right, key);
   8.381 +}*/
   8.382 +
   8.383 +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls)
   8.384 +{
   8.385 +	if(!node)
   8.386 +		return;
   8.387 +
   8.388 +	traverse(node->left, func, cls);
   8.389 +	func(node, cls);
   8.390 +	traverse(node->right, func, cls);
   8.391 +}
   8.392 +
   8.393 +/* helpers */
   8.394 +
   8.395 +static int is_red(struct rbnode *tree)
   8.396 +{
   8.397 +	return tree && tree->red;
   8.398 +}
   8.399 +
   8.400 +static void color_flip(struct rbnode *tree)
   8.401 +{
   8.402 +	tree->red = !tree->red;
   8.403 +	tree->left->red = !tree->left->red;
   8.404 +	tree->right->red = !tree->right->red;
   8.405 +}
   8.406 +
   8.407 +static struct rbnode *rot_left(struct rbnode *a)
   8.408 +{
   8.409 +	struct rbnode *b = a->right;
   8.410 +	a->right = b->left;
   8.411 +	b->left = a;
   8.412 +	b->red = a->red;
   8.413 +	a->red = 1;
   8.414 +	return b;
   8.415 +}
   8.416 +
   8.417 +static struct rbnode *rot_right(struct rbnode *a)
   8.418 +{
   8.419 +	struct rbnode *b = a->left;
   8.420 +	a->left = b->right;
   8.421 +	b->right = a;
   8.422 +	b->red = a->red;
   8.423 +	a->red = 1;
   8.424 +	return b;
   8.425 +}
   8.426 +
   8.427 +static struct rbnode *find_min(struct rbnode *tree)
   8.428 +{
   8.429 +	if(!tree)
   8.430 +		return 0;
   8.431 +
   8.432 +	while(tree->left) {
   8.433 +		tree = tree->left;
   8.434 +	}
   8.435 +	return tree;
   8.436 +}
   8.437 +
   8.438 +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree)
   8.439 +{
   8.440 +	if(!tree->left) {
   8.441 +		if(rb->del) {
   8.442 +			rb->del(tree->left, rb->del_cls);
   8.443 +		}
   8.444 +		rb->free(tree->left);
   8.445 +		return 0;
   8.446 +	}
   8.447 +
   8.448 +	/* make sure we've got red (3/4-nodes) at the left side so we can delete at the bottom */
   8.449 +	if(!is_red(tree->left) && !is_red(tree->left->left)) {
   8.450 +		tree = move_red_left(tree);
   8.451 +	}
   8.452 +	tree->left = del_min(rb, tree->left);
   8.453 +
   8.454 +	/* fix right-reds, red-reds, and split 4-nodes on the way up */
   8.455 +	return fix_up(tree);
   8.456 +}
   8.457 +
   8.458 +#if 0
   8.459 +/* push a red link on this node to the right */
   8.460 +static struct rbnode *move_red_right(struct rbnode *tree)
   8.461 +{
   8.462 +	/* flipping it makes both children go red, so we have a red to the right */
   8.463 +	color_flip(tree);
   8.464 +
   8.465 +	/* if after the flip we've got a red-red situation to the left, fix it */
   8.466 +	if(is_red(tree->left->left)) {
   8.467 +		tree = rot_right(tree);
   8.468 +		color_flip(tree);
   8.469 +	}
   8.470 +	return tree;
   8.471 +}
   8.472 +#endif
   8.473 +
   8.474 +/* push a red link on this node to the left */
   8.475 +static struct rbnode *move_red_left(struct rbnode *tree)
   8.476 +{
   8.477 +	/* flipping it makes both children go red, so we have a red to the left */
   8.478 +	color_flip(tree);
   8.479 +
   8.480 +	/* if after the flip we've got a red-red on the right-left, fix it */
   8.481 +	if(is_red(tree->right->left)) {
   8.482 +		tree->right = rot_right(tree->right);
   8.483 +		tree = rot_left(tree);
   8.484 +		color_flip(tree);
   8.485 +	}
   8.486 +	return tree;
   8.487 +}
   8.488 +
   8.489 +static struct rbnode *fix_up(struct rbnode *tree)
   8.490 +{
   8.491 +	/* fix right-leaning */
   8.492 +	if(is_red(tree->right)) {
   8.493 +		tree = rot_left(tree);
   8.494 +	}
   8.495 +	/* change invalid red-red pairs into a proper 4-node */
   8.496 +	if(is_red(tree->left) && is_red(tree->left->left)) {
   8.497 +		tree = rot_right(tree);
   8.498 +	}
   8.499 +	/* split 4-nodes */
   8.500 +	if(is_red(tree->left) && is_red(tree->right)) {
   8.501 +		color_flip(tree);
   8.502 +	}
   8.503 +	return tree;
   8.504 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/rbtree.h	Sun Nov 02 11:07:45 2014 +0200
     9.3 @@ -0,0 +1,78 @@
     9.4 +/*
     9.5 +rbtree - simple balanced binary search tree (red-black tree) library.
     9.6 +Copyright (C) 2011-2014  John Tsiombikas <nuclear@member.fsf.org>
     9.7 +
     9.8 +rbtree is free software, feel free to use, modify, and redistribute it, under
     9.9 +the terms of the 3-clause BSD license. See COPYING for details.
    9.10 + */
    9.11 +#ifndef RBTREE_H_
    9.12 +#define RBTREE_H_
    9.13 +
    9.14 +struct rbtree;
    9.15 +
    9.16 +
    9.17 +struct rbnode {
    9.18 +	void *key, *data;
    9.19 +	int red;
    9.20 +	struct rbnode *left, *right;
    9.21 +	struct rbnode *next;	/* for iterator stack */
    9.22 +};
    9.23 +
    9.24 +
    9.25 +typedef void *(*rb_alloc_func_t)(size_t);
    9.26 +typedef void (*rb_free_func_t)(void*);
    9.27 +
    9.28 +typedef int (*rb_cmp_func_t)(const void*, const void*);
    9.29 +typedef void (*rb_del_func_t)(struct rbnode*, void*);
    9.30 +
    9.31 +#define RB_KEY_ADDR		(rb_cmp_func_t)(0)
    9.32 +#define RB_KEY_INT		(rb_cmp_func_t)(1)
    9.33 +#define RB_KEY_STRING	(rb_cmp_func_t)(3)
    9.34 +
    9.35 +
    9.36 +#ifdef __cplusplus
    9.37 +extern "C" {
    9.38 +#endif
    9.39 +
    9.40 +struct rbtree *rb_create(rb_cmp_func_t cmp_func);
    9.41 +void rb_free(struct rbtree *rb);
    9.42 +
    9.43 +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func);
    9.44 +void rb_destroy(struct rbtree *rb);
    9.45 +
    9.46 +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free);
    9.47 +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func);
    9.48 +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls);
    9.49 +/* TODO add user deep copy function */
    9.50 +
    9.51 +void rb_clear(struct rbtree *rb);
    9.52 +int rb_copy(struct rbtree *dest, struct rbtree *src);
    9.53 +
    9.54 +int rb_size(struct rbtree *rb);
    9.55 +
    9.56 +int rb_insert(struct rbtree *rb, void *key, void *data);
    9.57 +int rb_inserti(struct rbtree *rb, int key, void *data);
    9.58 +
    9.59 +int rb_delete(struct rbtree *rb, void *key);
    9.60 +int rb_deletei(struct rbtree *rb, int key);
    9.61 +
    9.62 +struct rbnode *rb_find(struct rbtree *rb, void *key);
    9.63 +struct rbnode *rb_findi(struct rbtree *rb, int key);
    9.64 +
    9.65 +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls);
    9.66 +
    9.67 +struct rbnode *rb_root(struct rbtree *rb);
    9.68 +
    9.69 +void rb_begin(struct rbtree *rb);
    9.70 +struct rbnode *rb_next(struct rbtree *rb);
    9.71 +
    9.72 +void *rb_node_key(struct rbnode *node);
    9.73 +int rb_node_keyi(struct rbnode *node);
    9.74 +void *rb_node_data(struct rbnode *node);
    9.75 +
    9.76 +#ifdef __cplusplus
    9.77 +}
    9.78 +#endif
    9.79 +
    9.80 +
    9.81 +#endif	/* RBTREE_H_ */