Skip to content

Commit b855fd6

Browse files
author
Pascal MALAISE
committed
Add a function that lists subdivisions with same suffix
1 parent 190f809 commit b855fd6

5 files changed

Lines changed: 154 additions & 36 deletions

File tree

README.md

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,13 @@ attribute | description
150150
`Territory_Number` | `Territory_Range`
151151
return value | boolean, True if and only if the `Territory_Number` has some subdivisions
152152

153+
`Get_Subdivisions_With` returns the array of territories with the same suffix as provided.
154+
155+
attribute | description
156+
--- | ---
157+
`Territory_Number` | `Territory_Range`
158+
return value | array of `Territory_Range` that have the same subdivision name as the one of `Territory_Number`
159+
153160
## Converting a Coordinate into Mapcodes
154161

155162
In the mapcode system, territories are limited by rectangles, not by actual or
@@ -292,6 +299,7 @@ Usage:
292299
-h // This help
293300
-t <territory> // Territory info
294301
-s <name> // Search territory
302+
-S <name> // Subdirectories
295303
-d <territory_mapcode> // Decode
296304
-c <lat> <lon> [ <options> ] // Encode
297305
-a <territory_mapcode> [ <options> ] // Alternative mapcodes
@@ -310,20 +318,35 @@ and Shortest => True and to display the first entry of the returnd array.
310318

311319
Examples:
312320

313-
Put information on a territory (providing ISO code or number). The information consists in the
314-
territory number, followed by three possible mapcodes (Local, International and Shortest), followed by the territory full name.
321+
Put information on a territory (providing ISO code or number). The information consists in the territory number, followed by three possible mapcodes (Local, International and Shortest), followed by the territory full name.
315322

316323
t_mapcode -t KIR
317324
-> KIR => 58: KIR/KIR/KIR/Kiribati
318325

319326
t_mapcode -t CA
320327
-> CA => 391: CA/US-CA/CA/California
321-
-> Parent: USA
328+
-> Parent: USA
322329

323330
t_mapcode -t 410
324331
-> USA => 410: USA/USA/USA/USA
325-
-> Has subdivisions
332+
-> Has subdivisions
333+
334+
Search a territory by name.
335+
336+
t_mapcode -s alabama
337+
-> 364 => 364: AL/US-AL/US-AL/Alabama
338+
-> Parent: USA
339+
340+
List all subdivisions named "xx-AL".
326341

342+
t_mapcode -S AL
343+
-> US-AL => 364: AL/US-AL/US-AL/Alabama
344+
-> Parent: USA
345+
-> BR-AL => 318: AL/BR-AL/BR-AL/Alagoas
346+
-> Parent: BRA
347+
-> RU-AL => 482: AL/RU-AL/RU-AL/Altai Republic
348+
-> Parent: RUS
349+
327350
Encode a coordinate with a context and a precision, put information of the shortest mapcode.
328351
Information is the mapcode, the territory context of the mapcode, the full mapcode (territory
329352
and mapcode separated by a space and enclosed by quotes, except for international mapcodes) and territory number.

src/mapcodes.adb

Lines changed: 79 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -611,24 +611,38 @@ package body Mapcodes is
611611
Ccode_Rus : constant := 496;
612612
Ccode_Earth : constant := 532;
613613

614-
Parents3 : constant String := "USA,IND,CAN,AUS,MEX,BRA,RUS,CHN,";
615-
Parents2 : constant String := "US,IN,CA,AU,MX,BR,RU,CN,";
614+
-- Parent territories
615+
Parent_Length : constant := 8;
616+
subtype String3 is String (1 .. 3);
617+
Parents3 : constant array (1 .. Parent_Length) of String3
618+
:= ("USA", "IND", "CAN", "AUS", "MEX", "BRA", "RUS", "CHN");
619+
subtype String2 is String (1 .. 2);
620+
Parents2 : constant array (1 .. Parent_Length) of String2
621+
:= ("US", "IN", "CA", "AU", "MX", "BR", "RU", "CN");
616622

617623
-- Returns 2-letter parent country abbreviation (disam in range 1..8)
618624
function Parent_Name2 (Disam : Positive) return String is
619-
(Parents2 (Disam * 3 - 2 .. Disam * 3 - 1));
625+
(Parents2 (Disam));
620626

621627
-- Given a parent country abbreviation, return disam (in range 1-8) or
622628
-- Error
623629
function Parent_Letter (Territory_Alpha_Code : String) return Integer is
624-
Srch : constant String := Str_Tools.Upper_Str (Territory_Alpha_Code & ",");
625-
Len : constant Natural := Srch'Length;
626-
P : Natural;
630+
Srch : constant String := Str_Tools.Upper_Str (Territory_Alpha_Code);
627631
begin
628-
P := Str_Tools.Locate (
629-
(if Len = 3 then Parents2 elsif Len = 4 then Parents3 else Undefined),
630-
Srch);
631-
return (if P /= 0 then P / Len + 1 else Error);
632+
if Srch'Length = 2 then
633+
for I in Parents2'Range loop
634+
if Srch = Parents2(I) then
635+
return I;
636+
end if;
637+
end loop;
638+
elsif Srch'Length = 3 then
639+
for I in Parents3'Range loop
640+
if Srch = Parents3(I) then
641+
return I;
642+
end if;
643+
end loop;
644+
end if;
645+
return Error;
632646
end Parent_Letter;
633647

634648
function Image (I : Integer) return String is
@@ -680,7 +694,8 @@ package body Mapcodes is
680694

681695
-- Given ISO code, return territoryNumber or Error
682696
function Iso2Ccode (Territory_Alpha_Code : String;
683-
Context : in String) return Integer is
697+
Context : in String;
698+
Any_Context : in Boolean) return Integer is
684699
function Is_Digits (Str : String) return Boolean is
685700
begin
686701
for I in Str'Range loop
@@ -718,6 +733,7 @@ package body Mapcodes is
718733
-- Name
719734
Sep := Str_Tools.Locate (Alpha_Code.Image, "-");
720735
if Sep /= 0 then
736+
-- Territory and subdivision
721737
declare
722738
Prefix : constant String
723739
:= Alpha_Code.Slice (1, Sep - 1);
@@ -754,7 +770,6 @@ package body Mapcodes is
754770
end if;
755771

756772
-- No prefix.
757-
758773
if P /= Error then
759774
-- First rewrite alias in context
760775
if Alpha_Code.Length = 2 then
@@ -785,8 +800,12 @@ package body Mapcodes is
785800
end if;
786801
end if;
787802

803+
if not Any_Context then
804+
return Error;
805+
end if;
806+
788807
if Alpha_Code.Length >= 2 then
789-
-- Find in ANY context
808+
-- Find first occurence in ANY context
790809
Hyphenated := Tus ("-") & Alpha_Code;
791810
for I in Iso3166Alpha'Range loop
792811
Index := Str_Tools.Locate (Iso3166Alpha(I).Image, Hyphenated.Image);
@@ -808,7 +827,7 @@ package body Mapcodes is
808827
else
809828
Alpha_Code := Isoa;
810829
end if;
811-
return Iso2Ccode (Alpha_Code.Image, Context);
830+
return Iso2Ccode (Alpha_Code.Image, Context, True);
812831
end if;
813832

814833
return Error;
@@ -823,7 +842,7 @@ package body Mapcodes is
823842
return Territory_Range is
824843
Num : Integer;
825844
begin
826-
Num := Iso2Ccode (Territory, Context);
845+
Num := Iso2Ccode (Territory, Context, True);
827846
if Num = Error then
828847
raise Unknown_Territory;
829848
end if;
@@ -847,7 +866,7 @@ package body Mapcodes is
847866

848867
-- Return the AlphaCode (usually an ISO 3166 code) of a territory
849868
-- Format: Local (often ambiguous), International (full and unambiguous,
850-
-- DEFAULT), or Shortest (
869+
-- DEFAULT), or Shortest
851870
function Get_Territory_Alpha_Code (
852871
Territory_Number : Territory_Range;
853872
Format : Territory_Formats := International) return String is
@@ -912,6 +931,7 @@ package body Mapcodes is
912931
return Code;
913932
end if;
914933
end Get_Parent_Of;
934+
915935
-- Return True if Territory is a state
916936
function Is_Subdivision (Territory_Number : Territory_Range)
917937
return Boolean is
@@ -920,8 +940,49 @@ package body Mapcodes is
920940
-- Return True if Territory is a country that has states
921941
function Has_Subdivision (Territory_Number : Territory_Range)
922942
return Boolean is
923-
(Str_Tools.Locate (Parents3, Get_Territory_Alpha_Code (Territory_Number))
924-
/= 0);
943+
Territory : constant String := Get_Territory_Alpha_Code (Territory_Number);
944+
begin
945+
for Parent of Parents3 loop
946+
if Territory = Parent then
947+
return True;
948+
end if;
949+
end loop;
950+
return False;
951+
end Has_Subdivision;
952+
953+
-- Given a subdivision, return the array of subdivisions with same name
954+
-- with various parents, or raise Not_A_Subdivision
955+
function Get_Subdivisions_With (Territory_Number : Territory_Range)
956+
return Territory_Array is
957+
Territory : constant String := Get_Territory_Alpha_Code (Territory_Number);
958+
Index : Natural;
959+
Ccodes : array (1 .. Parent_Length) of Integer;
960+
Nb_Ok : Natural := 0;
961+
begin
962+
-- Get subdivision part (after '-')
963+
Index := Str_Tools.Locate (Territory, "-");
964+
if Index = 0 then
965+
raise Not_A_Subdivision;
966+
end if;
967+
-- Count and store valid combinations of a Parent and this subdivision
968+
for I in Parents2'Range loop
969+
Ccodes(I) := Iso2Ccode (Territory (Index + 1 .. Territory'Last),
970+
Parents2(I), False);
971+
if Ccodes(I) /= Error then
972+
Nb_Ok := Nb_Ok + 1;
973+
end if;
974+
end loop;
975+
-- Return array of valid combinations
976+
return Result : Territory_Array (1 .. Nb_Ok) do
977+
Nb_Ok := 0;
978+
for Ccode of Ccodes loop
979+
if Ccode /= Error then
980+
Nb_Ok := Nb_Ok + 1;
981+
Result(Nb_Ok) := Ccode;
982+
end if;
983+
end loop;
984+
end return;
985+
end Get_Subdivisions_With;
925986

926987
-- Low-level routines for data access
927988
type Min_Max_Rec is record

src/mapcodes.ads

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,29 +33,31 @@ package Mapcodes is
3333
-- Valid territory number
3434
subtype Territory_Range is Natural range 0 .. Ctrynams.Isofullname'Last - 1;
3535

36-
-- Given an alphacode (such as US-AL), return the territory number
37-
-- or raise Unknown_Territory
36+
-- Given an ISO 3166 alphacode (such as "US-AL" or "FRA"), return the
37+
-- corresponding territory number or raise Unknown_Territory
3838
-- A Context territory helps to interpret ambiguous (abbreviated)
39-
-- alphacodes, such as "AL"
39+
-- alphacodes, such as "BR" or "US" for the subdivision "AL"
40+
-- If Territory is ambiguous and no Context is provided, then the first
41+
-- (in the alphanumeric order of territories) valid territory is used
4042
-- Raise, if Territory or Context is not known:
4143
Unknown_Territory : exception;
4244
function Get_Territory_Number (Territory : String;
4345
Context : String := "")
4446
return Territory_Range;
4547

46-
-- Return the alphacode (usually an ISO 3166 code) of a territory
48+
-- Return the alphacode (usually an ISO 3166 code) of a territory number
4749
-- Format: Local (often ambiguous), International (full and unambiguous,
4850
-- DEFAULT), or Shortest
4951
type Territory_Formats is (Local, International, Shortest);
5052
function Get_Territory_Alpha_Code (
5153
Territory_Number : Territory_Range;
5254
Format : Territory_Formats := International) return String;
5355

54-
-- Return the full name of a territory
56+
-- Return the full readable name of a territory (e.g. "France")
5557
function Get_Territory_Fullname (Territory_Number : Territory_Range)
5658
return String;
5759

58-
-- Return the parent country of a subdivision
60+
-- Return the parent country of a subdivision (e.g. "US" for "US-AL"
5961
-- Raise, if Territory is not a subdivision:
6062
Not_A_Subdivision : exception;
6163
function Get_Parent_Of (Territory_Number : Territory_Range)
@@ -67,6 +69,14 @@ package Mapcodes is
6769
-- Return True if Territory is a country that has states
6870
function Has_Subdivision (Territory_Number : Territory_Range) return Boolean;
6971

72+
-- Given a subdivision, return the array of subdivisions with same name
73+
-- with various parents, or raise Not_A_Subdivision
74+
-- Ex: given 318 (BR-AL) or 482 (RU-AL) returns the array
75+
-- (318 (BR-AL), 482 (RU-AL), 364 (US-AL))
76+
type Territory_Array is array (Positive range <>) of Territory_Range;
77+
function Get_Subdivisions_With (Territory_Number : Territory_Range)
78+
return Territory_Array;
79+
7080
--------------------------
7181
-- Encoding to mapcodes --
7282
--------------------------

src/t_mapcode.adb

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ procedure T_Mapcode is
3434
" -t <territory> // Territory info");
3535
Ada.Text_Io.Put_Line (
3636
" -s <name> // Search territory");
37+
Ada.Text_Io.Put_Line (
38+
" -S <name> // Subdirectories");
3739
Ada.Text_Io.Put_Line (
3840
" -d <territory_mapcode> // Decode");
3941
Ada.Text_Io.Put_Line (
@@ -77,7 +79,8 @@ procedure T_Mapcode is
7779
return Result;
7880
end Lower_Str;
7981

80-
procedure Put_Territory (Territory, Context : in String) is
82+
procedure Put_Territory (Territory, Context : in String;
83+
Show_Subdivision : in Boolean) is
8184
Index : Mapcodes.Territory_Range;
8285
begin
8386
Ada.Text_Io.Put (Territory
@@ -90,17 +93,17 @@ procedure T_Mapcode is
9093
& "/" & Get_Territory_Alpha_Code (Index, Mapcodes.Shortest)
9194
& "/" & Get_Territory_Fullname (Index) );
9295
if Is_Subdivision (Index) then
93-
Ada.Text_Io.Put_Line ("Parent: "
96+
Ada.Text_Io.Put_Line (" Parent: "
9497
& Get_Territory_Alpha_Code (Get_Parent_Of (Index)));
9598
end if;
96-
if Has_Subdivision (Index) then
97-
Ada.Text_Io.Put_Line ( "Has subdivisions");
99+
if Show_Subdivision and then Has_Subdivision (Index) then
100+
Ada.Text_Io.Put_Line ( " Has subdivisions");
98101
end if;
99102
end Put_Territory;
100103

101104
function Is_Command (Arg : in String) return Boolean is
102-
(Arg = "-h" or else Arg = "-t" or else Arg = "-c" or else Arg = "-d"
103-
or else Arg = "-a");
105+
(Arg = "-h" or else Arg = "-t" or else Arg = "-s" or else Arg = "-S"
106+
or else Arg = "-d" or else Arg = "-c" or else Arg = "-a");
104107

105108
function Image (F : Mapcodes.Real) return String is
106109
begin
@@ -119,6 +122,9 @@ procedure T_Mapcode is
119122
function Get (Str : String) return Mapcodes.Real is
120123
begin
121124
return Mapcodes.Real'Value (Str);
125+
exception
126+
when Constraint_Error =>
127+
raise Argument_Error;
122128
end Get;
123129

124130
I : Positive;
@@ -190,7 +196,7 @@ begin
190196
I := I + 1;
191197
end if;
192198
end if;
193-
Put_Territory (Arg1.Image, Arg2.Image);
199+
Put_Territory (Arg1.Image, Arg2.Image, True);
194200
elsif Command.Image = "-s" then
195201
-- Search country names
196202
I := I + 1;
@@ -199,9 +205,22 @@ begin
199205
if Str_Tools.Locate (Str_Tools.Upper_Str
200206
(Ctrynams.Isofullname(J).Image),
201207
Territory.Image) /= 0 then
202-
Put_Territory (Image (J-1), "");
208+
Put_Territory (Image (J-1), "", True);
203209
end if;
204210
end loop;
211+
elsif Command.Image = "-S" then
212+
I := I + 1;
213+
-- Subdirectories with same suffix
214+
declare
215+
Brothers : constant Mapcodes.Territory_Array
216+
:= Mapcodes.Get_Subdivisions_With (
217+
Get_Territory_Number (Ada.Command_Line.Argument (I)));
218+
begin
219+
for Brother of Brothers loop
220+
Put_Territory (Mapcodes.Get_Territory_Alpha_Code (Brother), "",
221+
False);
222+
end loop;
223+
end;
205224
elsif Command.Image = "-c"
206225
or else Command.Image = "-a" then
207226
-- Default precision for coding
@@ -318,6 +337,9 @@ exception
318337
Ada.Text_Io.Put_Line (Ada.Text_Io.Standard_Error,
319338
"Raised Unknown_Territory");
320339
Ada.Command_Line.Set_Exit_Status (1);
340+
when Mapcodes.Not_A_Subdivision =>
341+
Ada.Text_Io.Put_Line (Ada.Text_Io.Standard_Error,
342+
"Raised Not_A_Subdivision");
321343
when Mapcodes.Decode_Error =>
322344
Ada.Text_Io.Put_Line (Ada.Text_Io.Standard_Error, "Raised Decode_Error");
323345
Ada.Command_Line.Set_Exit_Status (1);

test/Scenario

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
-t IN-MN => 279: MN/IN-MN/IN-MN/Manipur Parent: IND
4242
-t US-IN => 356: IN/US-IN/US-IN/Indiana Parent: USA
4343
-t NLD => 112: NLD/NLD/NLD/Netherlands
44+
-s altai => 483: ALT/RU-ALT/ALT/Altai Krai Parent: RUS
45+
-S AL => 482: AL/RU-AL/RU-AL/Altai Republic Parent: RUS
4446

4547
# NLD, with high precision
4648
-d NLD 49.4V => 52.376514000 4.908543375

0 commit comments

Comments
 (0)