-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhetu.c
executable file
·192 lines (154 loc) · 4.48 KB
/
hetu.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/* Tämä ohjelma tarkistaa henkilötunnuksen oikeellisuuden. Sen on
kirjoittanut Antti-Juhani Kaijanaho ([email protected]) 1999-02-21.
Ohjelmaa saadaan käyttää, muuttaa ja levittää vapaasti, kunhan
ohjeman tekijä ja mahdollisten muutosten tekijät mainitaan
asianmukaisesti.
Henkilötunnus luetaan komentoriviltä. Sen oikeellisuus tulostetaan
standardisyötevirtaan, ja ohjelman paluuarvo kertoo onnistumisesta
vain silloin, kun kaikki annnetut henkilötunnukset ovat OK.
Henkilötunnuksen tarkistusmerkin oletetaan olevan joko suuraakkonen
tai numero.
Ohjelma on pyritty kirjoittamaan ISO-standardin mukaisella C:llä.
Ohjelman teossa on pyritty välttämään oletuksia käytössä olevasta
ympäristöstä (esim. merkistöasiat), joten ohjelman pitäisi olla
maksimaalisen portattava.
OHJELMAN TEKIJÄ EI OTA OHJELMAN TOIMINNAN OIKEELLISUUDESTA
MINKÄÄNLAISTA VASTUUTA.
Muutokset tiedoston lopussa.
Tämä ohjelma on osa sfnet.atk.ohjelmointi.moderoitu-uutisryhmän FAQ:a.
Sen uusin versio on saatavissa FAQ:n seittisivun
<URL: http://www.iki.fi/gaia/faq/sao-faq.html >
kautta. Ohjelma voi löytyä myös osoitteesta
<URL: ftp://ftp.jyu.fi/private/antkaij/faq/hetu.c >
*/
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Palauttaa toden, mikäli b jakaa a:n. */
int
jakaa (int a, int b)
{
return a % b == 0;
}
/* Palauttaa toden, mikäli n on a:n ja b:n välissä. Oletus: a <= b.*/
int
valissa (int n, int a, int b)
{
assert (a <= b);
return a <= n && n <= b;
}
/* Toimii vain gregoriaanisella kalenterilla. Gregoriaaninen
kalenteri syntyi 1582. */
int
karkausvuosi (int vuosi)
{
assert (vuosi >= 1582);
return (jakaa (vuosi, 4) && (!jakaa (vuosi, 100) || jakaa (vuosi, 400)));
}
/* Onko päiväys p.kk.v validi? */
int
paivays_ok (int p, int kk, int v)
{
/* Tämä on päiviä kuukaudessa -taulukko; ensimmäinen dimensio
valitsee karkausvuoden (1) ja tavallisen vuoden (0) välillä. */
static p_kk [2] [12] = {
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } };
return valissa (kk, 1, 12)
&& valissa (p, 1, p_kk [karkausvuosi (v) ? 1 : 0] [kk - 1]);
}
/* Muutetaan numeromerki c numeroksi. Mikäli c ei ole numeromerkki,
palautetaan INT_MIN. */
int
char2digit (char c)
{
switch (c)
{
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
default:
return INT_MIN;
}
}
/* Muutetaan merkkijono s (josta huomioidaan enintään n merkkiä ja
merkki ignore jätetään huomiotta) ei-negatiiviseksi luvuksi.
Palautetaan LONG_MIN virhetapauksessa. */
long
str2long (const char * s, size_t n, int ignore)
{
long rv = 0;
int i;
assert (s != 0);
for (i = 0; s [i] != 0 && i < n; i++)
{
int c2d;
if (i == ignore)
continue;
c2d = char2digit (s [i]);
if (c2d == INT_MIN)
return LONG_MIN;
rv = rv * 10 + c2d;
}
return rv;
}
int
hetu_ok (const char * hetu)
{
int vuosisata;
const int VSM = 6; /* vuosisatamerkin indeksi */
const int TM = 10; /* tarkistemerkin indeksi */
static const char tarkmerk [] = "0123456789ABCDEFHJKLMNPRSTUVWXY";
if (strlen (hetu) != TM + 1)
return 0;
/* Tarkistetaan vuosisatamerkki. */
switch (hetu [VSM])
{
case '-':
vuosisata = 1900; break;
case '+':
vuosisata = 1800; break;
case 'A':
vuosisata = 2000; break;
default:
return 0;
}
/* Tarkistetaan päiväys. */
if (!paivays_ok (str2long (hetu, 2, -1),
str2long (hetu + 2, 2, -1),
str2long (hetu + 4, 2, -1) + vuosisata))
return 0;
/* Tarkistetaan tarkiste. */
return hetu [TM] == tarkmerk [str2long (hetu, TM, VSM) % 31];
}
int
main (int argc, char * argv [])
{
int i;
int rv = EXIT_SUCCESS;
for (i = 1; i < argc; i++)
{
int ok;
ok = hetu_ok (argv[i]);
printf ("%s: %s\n", argv [i], ok ? "OK" : "Virhe");
rv = ok ? rv : EXIT_FAILURE;
}
return rv;
}
/*
$Log: hetu.c,v $
Revision 1.2 1999/12/10 03:32:11 ajk
Mainitaan oletus, että tarkistemerkki ei ole pienaakkonen. Mainitaan
ohjelman suhde sao-faq:iin ja sen URL.
1999-02-21 [email protected]: paivays_ok
Korjattu off by one -virhe taulukon indeksoinnissa.
*/