]> andersk Git - splint.git/blob - src/varKinds.c
Initial revision
[splint.git] / src / varKinds.c
1 /*
2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2000 University of Virginia,
4 **         Massachusetts Institute of Technology
5 **
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
10 ** 
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 ** General Public License for more details.
15 ** 
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
19 **
20 ** For information on lclint: lclint-request@cs.virginia.edu
21 ** To report a bug: lclint-bug@cs.virginia.edu
22 ** For more information: http://lclint.cs.virginia.edu
23 */
24 /*
25 ** varKinds.c
26 */
27
28 # include "lclintMacros.nf"
29 # include "basic.h"
30
31 alkind alkind_fromInt (int n)
32 {
33   /*@+enumint@*/
34   llassert (n >= AK_UNKNOWN && n <= AK_LOCAL);
35   /*@=enumint@*/
36
37   return ((alkind)n);
38 }
39
40 nstate nstate_fromInt (int n)
41 {
42   /*@+enumint@*/
43   llassert (n >= NS_ERROR && n <= NS_ABSNULL);
44   /*@=enumint@*/
45
46   return ((nstate)n);
47 }
48
49 sstate sstate_fromInt (int n)
50 {
51   /*@+enumint@*/
52   llassert (n >= SS_UNKNOWN && n < SS_LAST);
53   /*@=enumint@*/
54
55   return ((sstate)n);
56 }
57
58 exkind exkind_fromInt (int n)
59 {
60   /*@+enumint@*/
61   llassert (n >= XO_UNKNOWN && n <= XO_OBSERVER);
62   /*@=enumint@*/
63
64   return ((exkind) n);
65 }
66
67 cstring sstate_unparse (sstate s)
68 {
69   switch (s)
70     {
71     case SS_UNKNOWN:   return cstring_makeLiteralTemp ("unknown");
72     case SS_UNUSEABLE: return cstring_makeLiteralTemp ("unuseable");
73     case SS_UNDEFINED: return cstring_makeLiteralTemp ("undefined");
74     case SS_MUNDEFINED:return cstring_makeLiteralTemp ("possibly undefined");
75     case SS_ALLOCATED: return cstring_makeLiteralTemp ("allocated");
76     case SS_PDEFINED:  return cstring_makeLiteralTemp ("partially defined");
77     case SS_DEFINED:   return cstring_makeLiteralTemp ("defined");
78     case SS_PARTIAL:   return cstring_makeLiteralTemp ("partial");
79     case SS_SPECIAL:   return cstring_makeLiteralTemp ("special");
80     case SS_DEAD:      return cstring_makeLiteralTemp ("dead");
81     case SS_HOFFA:     return cstring_makeLiteralTemp ("probably dead");
82     case SS_FIXED:     return cstring_makeLiteralTemp ("unmodifiable");
83     case SS_RELDEF:    return cstring_makeLiteralTemp ("reldef");
84     case SS_LAST:      llcontbuglit ("sstate_unparse: last");
85                        return cstring_makeLiteralTemp ("<error>");
86     case SS_UNDEFGLOB:     return cstring_makeLiteralTemp ("undefglob");
87     case SS_KILLED:    return cstring_makeLiteralTemp ("killed");
88     case SS_UNDEFKILLED:
89       return cstring_makeLiteralTemp ("undefkilled");
90     }
91
92   BADEXIT;
93 }
94
95 bool nstate_possiblyNull (nstate n)
96 {
97   /*
98   ** note: not NS_UNKNOWN or NS_ERROR 
99   */
100
101   return ((n >= NS_CONSTNULL) && (n <= NS_ABSNULL));
102 }
103
104 bool nstate_perhapsNull (nstate n)
105 {
106   /*
107   ** note: not NS_UNKNOWN or NS_ERROR 
108   */
109
110   return ((n >= NS_RELNULL) && (n <= NS_ABSNULL));
111 }
112
113 cstring nstate_unparse (nstate n)
114 {
115   switch (n)
116     {
117     case NS_ERROR:     return cstring_makeLiteralTemp ("<null error>");
118     case NS_UNKNOWN:   return cstring_makeLiteralTemp ("implicitly non-null");
119     case NS_POSNULL:   return cstring_makeLiteralTemp ("null");
120     case NS_DEFNULL:   return cstring_makeLiteralTemp ("null");
121     case NS_NOTNULL:   return cstring_makeLiteralTemp ("notnull");
122     case NS_MNOTNULL:  return cstring_makeLiteralTemp ("notnull");
123     case NS_ABSNULL:   return cstring_makeLiteralTemp ("null");
124     case NS_RELNULL:   return cstring_makeLiteralTemp ("relnull");
125     case NS_CONSTNULL: return cstring_makeLiteralTemp ("null");
126     }
127
128   BADEXIT;
129 }
130
131 /*
132 ** ??? (used to do something different for guarded)
133 */
134
135 int nstate_compare (nstate n1, nstate n2)
136 {
137   return (generic_compare (n1, n2));
138 }
139
140 /*
141 ** This occurs when we select a field with alkind inner, 
142 ** from a structure with alkind outer.  It is probably
143 ** unnecessary.
144 */
145
146 alkind alkind_derive (alkind outer, alkind inner)
147 {
148   switch (outer)
149     {
150     case AK_ERROR:
151     case AK_UNKNOWN: return inner;
152     case AK_KEPT:
153     case AK_KEEP:
154     case AK_ONLY: 
155     case AK_IMPONLY:
156     case AK_OWNED:
157     case AK_IMPDEPENDENT:
158     case AK_DEPENDENT:
159       if (inner == AK_SHARED) return AK_SHARED;
160       else return outer;
161       /* not so sure about these? */
162     case AK_REFCOUNTED:
163     case AK_NEWREF:
164     case AK_KILLREF:
165     case AK_REFS:
166     case AK_STACK:
167     case AK_STATIC:
168       return outer;
169     case AK_TEMP: 
170     case AK_IMPTEMP:
171     case AK_SHARED:
172     case AK_UNIQUE:
173     case AK_LOCAL: 
174     case AK_FRESH:
175     case AK_RETURNED:
176       if (alkind_isKnown (inner)) return inner; 
177       else return outer;
178     }
179   BADEXIT;
180 }
181
182 cstring alkind_unparse (alkind a)
183 {
184   switch (a)
185     {
186     case AK_ERROR:           return cstring_makeLiteralTemp ("<error>");
187     case AK_UNKNOWN:         return cstring_makeLiteralTemp ("unqualified");
188     case AK_ONLY:            return cstring_makeLiteralTemp ("only");
189     case AK_IMPONLY:         return cstring_makeLiteralTemp ("implicitly only");
190     case AK_OWNED:           return cstring_makeLiteralTemp ("owned");
191     case AK_IMPDEPENDENT:    return cstring_makeLiteralTemp ("implicitly dependent");
192     case AK_DEPENDENT:       return cstring_makeLiteralTemp ("dependent");
193     case AK_KEEP:            return cstring_makeLiteralTemp ("keep");
194     case AK_KEPT:            return cstring_makeLiteralTemp ("kept");
195     case AK_IMPTEMP:         return cstring_makeLiteralTemp ("implicitly temp");
196     case AK_TEMP:            return cstring_makeLiteralTemp ("temp");
197     case AK_SHARED:          return cstring_makeLiteralTemp ("shared");
198     case AK_UNIQUE:          return cstring_makeLiteralTemp ("unique");
199     case AK_RETURNED:        return cstring_makeLiteralTemp ("returned");
200     case AK_FRESH:           return cstring_makeLiteralTemp ("fresh");
201     case AK_STACK:           return cstring_makeLiteralTemp ("stack");
202     case AK_REFCOUNTED:      return cstring_makeLiteralTemp ("refcounted");
203     case AK_REFS:            return cstring_makeLiteralTemp ("refs");
204     case AK_KILLREF:         return cstring_makeLiteralTemp ("killref");
205     case AK_NEWREF:          return cstring_makeLiteralTemp ("newref");
206     case AK_LOCAL:           return cstring_makeLiteralTemp ("local");
207     case AK_STATIC:          return cstring_makeLiteralTemp ("unqualified static");
208     }
209     BADEXIT;
210 }
211
212 cstring exkind_unparse (exkind a)
213 {
214   switch (a)
215     {
216     case XO_UNKNOWN:         return cstring_makeLiteralTemp ("unknown");
217     case XO_NORMAL:          return cstring_makeLiteralTemp ("unexposed");
218     case XO_EXPOSED:         return cstring_makeLiteralTemp ("exposed");
219     case XO_OBSERVER:        return cstring_makeLiteralTemp ("observer");
220     }
221   BADEXIT;
222 }
223
224 cstring exkind_capName (exkind a)
225 {
226   switch (a)
227     {
228     case XO_UNKNOWN:         return cstring_makeLiteralTemp ("Unknown");
229     case XO_NORMAL:          return cstring_makeLiteralTemp ("Unexposed");
230     case XO_EXPOSED:         return cstring_makeLiteralTemp ("Exposed");
231     case XO_OBSERVER:        return cstring_makeLiteralTemp ("Observer");
232     }
233   BADEXIT;
234 }
235
236 cstring exkind_unparseError (exkind a)
237 {
238   switch (a)
239     {
240     case XO_UNKNOWN:         return cstring_makeLiteralTemp ("unqualified");
241     case XO_NORMAL:          return cstring_makeLiteralTemp ("unqualifier");
242     case XO_EXPOSED:         return cstring_makeLiteralTemp ("exposed");
243     case XO_OBSERVER:        return cstring_makeLiteralTemp ("observer");
244     }
245   BADEXIT;
246 }
247
248 cstring alkind_capName (alkind a)
249 {
250   switch (a)
251     {
252     case AK_ERROR:    
253       return cstring_makeLiteralTemp ("<Error>");
254     case AK_UNKNOWN:     
255       return cstring_makeLiteralTemp ("Unqualified");
256     case AK_ONLY:  
257       return cstring_makeLiteralTemp ("Only");
258     case AK_IMPONLY:
259       return cstring_makeLiteralTemp ("Implicitly only");
260     case AK_OWNED:
261       return cstring_makeLiteralTemp ("Owned");
262     case AK_IMPDEPENDENT:  
263       return cstring_makeLiteralTemp ("Implicitly dependent");
264     case AK_DEPENDENT:  
265       return cstring_makeLiteralTemp ("Dependent");
266     case AK_KEEP:     
267       return cstring_makeLiteralTemp ("Keep");
268     case AK_KEPT:    
269       return cstring_makeLiteralTemp ("Kept");
270     case AK_IMPTEMP:   
271       return cstring_makeLiteralTemp ("Implicitly temp");
272     case AK_TEMP:    
273       return cstring_makeLiteralTemp ("Temp");
274     case AK_SHARED:
275       return cstring_makeLiteralTemp ("Shared");
276     case AK_UNIQUE:    
277       return cstring_makeLiteralTemp ("Unique");
278     case AK_RETURNED:
279       return cstring_makeLiteralTemp ("Returned");
280     case AK_FRESH:   
281       return cstring_makeLiteralTemp ("Fresh");
282     case AK_STACK:      
283       return cstring_makeLiteralTemp ("Stack");
284     case AK_REFCOUNTED: 
285       return cstring_makeLiteralTemp ("Refcounted");
286     case AK_REFS:
287       return cstring_makeLiteralTemp ("Refs");
288     case AK_KILLREF: 
289       return cstring_makeLiteralTemp ("Killref");
290     case AK_NEWREF:    
291       return cstring_makeLiteralTemp ("Newref");
292     case AK_LOCAL:    
293       return cstring_makeLiteralTemp ("Local");
294     case AK_STATIC: 
295       return cstring_makeLiteralTemp ("Unqualified static");
296     }
297   BADEXIT;
298 }
299
300 exkind
301 exkind_fromQual (qual q)
302 {
303   if (qual_isExposed (q))     return XO_EXPOSED;
304   if (qual_isObserver (q))    return XO_OBSERVER;
305   else
306     {
307       llcontbug (message ("exkind_fromQual: not exp qualifier: %d" , (int)q));
308       return XO_UNKNOWN;
309     }
310 }
311
312 sstate
313 sstate_fromQual (qual q)
314 {
315   if (qual_isOut (q))          return SS_ALLOCATED;
316   if (qual_isIn (q))           return SS_DEFINED;
317   else if (qual_isPartial (q)) return SS_PARTIAL;
318   else if (qual_isRelDef (q))  return SS_RELDEF;
319   else if (qual_isUndef (q))   return SS_UNDEFGLOB;
320   else if (qual_isKilled (q))  return SS_KILLED;
321   else if (qual_isSpecial (q)) return SS_SPECIAL;
322   else
323     {
324       llcontbug (message ("sstate_fromQual: not alias qualifier: %s (%d)" , 
325                           qual_unparse (q),
326                           (int)q));
327       return SS_UNKNOWN;
328     }
329 }
330
331 exitkind
332 exitkind_fromQual (qual q)
333 {
334   if (qual_isExits (q))     return XK_MUSTEXIT;
335   if (qual_isMayExit (q))   return XK_MAYEXIT;
336   if (qual_isTrueExit (q))  return XK_TRUEEXIT;
337   if (qual_isFalseExit (q)) return XK_FALSEEXIT;
338   if (qual_isNeverExit (q)) return XK_NEVERESCAPE;
339   else
340     {
341       llcontbug (message ("exitkind_fromQual: not exit qualifier: %s",
342                           qual_unparse (q)));
343       return XK_UNKNOWN;
344     }
345 }
346
347 alkind
348 alkind_fromQual (qual q)
349 {
350   if (qual_isOnly (q))       return AK_ONLY;
351   if (qual_isImpOnly (q))    return AK_IMPONLY;
352   if (qual_isKeep (q))       return AK_KEEP;
353   if (qual_isKept (q))       return AK_KEPT;
354   if (qual_isTemp (q))       return AK_TEMP;
355   if (qual_isShared (q))     return AK_SHARED;
356   if (qual_isUnique (q))     return AK_UNIQUE;
357   if (qual_isRefCounted (q)) return AK_REFCOUNTED;
358   if (qual_isRefs (q))       return AK_REFS;
359   if (qual_isNewRef (q))     return AK_NEWREF;
360   if (qual_isKillRef (q))    return AK_KILLREF;
361   if (qual_isTempRef (q))    return AK_KILLREF; /* kludge? use kill ref for this */
362   if (qual_isOwned (q))      return AK_OWNED;
363   if (qual_isDependent (q))  return AK_DEPENDENT;
364
365   llcontbug (message ("alkind_fromQual: not alias qualifier: %d" , (int)q));
366   return AK_ERROR;
367 }    
368
369 static bool alkind_isMeaningless (alkind a1)
370 {
371   return (a1 == AK_ERROR || a1 == AK_UNKNOWN || a1 == AK_RETURNED
372           || a1 == AK_STACK || a1 == AK_REFCOUNTED
373           || a1 == AK_REFS || a1 == AK_KILLREF || a1 == AK_NEWREF
374           || a1 == AK_LOCAL);
375 }
376
377 bool alkind_compatible (alkind a1, alkind a2)
378 {
379   if (a1 == a2) return TRUE;
380   if (a2 == AK_ERROR) return TRUE;
381   if (a2 == AK_UNKNOWN)
382     {
383       return (alkind_isMeaningless (a1) || (a1 == AK_IMPTEMP));
384     }
385
386   switch (a1)
387     {
388     case AK_ERROR:               return TRUE;
389     case AK_UNKNOWN:             return (alkind_isMeaningless (a2)
390                                          || (a2 == AK_IMPTEMP));
391     case AK_IMPONLY:             return (a2 == AK_KEEP || a2 == AK_FRESH 
392                                          || a2 == AK_ONLY);
393     case AK_ONLY:                return (a2 == AK_KEEP || a2 == AK_FRESH
394                                          || a2 == AK_IMPONLY);
395     case AK_OWNED:               return FALSE;
396     case AK_IMPDEPENDENT:        return (a2 == AK_DEPENDENT);
397     case AK_DEPENDENT:           return (a2 == AK_IMPDEPENDENT);
398     case AK_KEEP:                return (a2 == AK_ONLY || a2 == AK_FRESH
399                                          || a2 == AK_IMPONLY);
400     case AK_KEPT:                return FALSE;
401     case AK_IMPTEMP:             return (a2 == AK_TEMP);
402     case AK_TEMP:                return (a2 == AK_IMPTEMP);
403     case AK_SHARED:              return FALSE;
404     case AK_UNIQUE:              return (a2 == AK_TEMP);
405     case AK_RETURNED:            return (alkind_isMeaningless (a2));
406     case AK_FRESH:               return (alkind_isOnly (a2));
407     case AK_STACK:               return (alkind_isMeaningless (a2));
408     case AK_REFCOUNTED:          return (alkind_isMeaningless (a2));
409     case AK_REFS:                return (alkind_isMeaningless (a2));
410     case AK_KILLREF:             return (alkind_isMeaningless (a2));
411     case AK_NEWREF:              return (alkind_isMeaningless (a2));
412     case AK_LOCAL:               return (alkind_isMeaningless (a2));
413     case AK_STATIC:              return (alkind_isMeaningless (a2));
414     }
415   BADEXIT;
416 }
417
418 bool alkind_equal (alkind a1, alkind a2)
419 {
420   if (a1 == a2) return TRUE;
421   if (a2 == AK_ERROR) return TRUE;
422
423   switch (a1)
424     {
425     case AK_ERROR:               return TRUE;
426     case AK_IMPONLY:             return (a2 == AK_ONLY);
427     case AK_ONLY:                return (a2 == AK_IMPONLY);
428     case AK_IMPDEPENDENT:        return (a2 == AK_DEPENDENT);
429     case AK_DEPENDENT:           return (a2 == AK_IMPDEPENDENT);
430     case AK_IMPTEMP:             return (a2 == AK_TEMP);
431     case AK_TEMP:                return (a2 == AK_IMPTEMP);
432     default:                     return FALSE;
433     }
434
435   BADEXIT;
436 }
437
438 alkind
439 alkind_fixImplicit (alkind a)
440 {
441   if (a == AK_IMPTEMP) return AK_TEMP;
442   if (a == AK_IMPONLY) return AK_IMPONLY;
443   if (a == AK_IMPDEPENDENT) return AK_DEPENDENT;
444
445   return a;
446 }
447
448 cstring exitkind_unparse (exitkind k)
449 {
450   switch (k)
451     {
452     case XK_ERROR:       return (cstring_makeLiteralTemp ("<error>"));
453     case XK_UNKNOWN:     return (cstring_makeLiteralTemp ("?"));
454     case XK_NEVERESCAPE: return (cstring_makeLiteralTemp ("never escape"));
455     case XK_MAYEXIT:     return (cstring_makeLiteralTemp ("mayexit"));
456     case XK_MUSTEXIT:    return (cstring_makeLiteralTemp ("exits"));
457     case XK_TRUEEXIT:    return (cstring_makeLiteralTemp ("trueexit"));
458     case XK_FALSEEXIT:   return (cstring_makeLiteralTemp ("falseexit"));
459     case XK_MUSTRETURN:  return (cstring_makeLiteralTemp ("mustreturn"));
460     case XK_MAYRETURN:   return (cstring_makeLiteralTemp ("mayreturn"));
461     case XK_MUSTRETURNEXIT: return (cstring_makeLiteralTemp ("mustreturnexit"));
462     case XK_MAYRETURNEXIT: return (cstring_makeLiteralTemp ("mayreturnexit"));
463     case XK_GOTO:        return (cstring_makeLiteralTemp ("goto"));
464     case XK_MAYGOTO:     return (cstring_makeLiteralTemp ("maygoto"));
465     }
466   
467  BADEXIT;
468 }
469
470 exitkind exitkind_makeConditional (exitkind k)
471 {
472   switch (k)
473     {
474     case XK_TRUEEXIT:
475     case XK_FALSEEXIT: 
476     case XK_MUSTEXIT:       return XK_MAYEXIT;
477     case XK_MUSTRETURN:     return XK_MAYRETURN;
478     case XK_MUSTRETURNEXIT: return XK_MAYRETURNEXIT;
479     case XK_GOTO:           return XK_MAYGOTO;
480     default:                return k;
481     }
482 }
483
484 exitkind exitkind_combine (exitkind k1, exitkind k2)
485 {
486   if (k1 == k2)
487     {
488       return k1;
489     }
490
491   if (k2 == XK_ERROR)
492     {
493       return XK_ERROR;
494     }
495
496   switch (k1)
497     {
498     case XK_ERROR: return XK_ERROR;
499     case XK_UNKNOWN:     
500     case XK_NEVERESCAPE: return (exitkind_makeConditional (k2));
501     case XK_MUSTEXIT:    
502       switch (k2)
503         {
504         case XK_MUSTRETURNEXIT:
505         case XK_MUSTRETURN: return XK_MUSTRETURNEXIT;
506         case XK_MAYRETURNEXIT:
507         case XK_MAYRETURN:  return XK_MAYRETURNEXIT;
508         default:             return XK_MAYEXIT;
509         }
510       BADEXIT;
511
512     case XK_MAYEXIT:     
513     case XK_TRUEEXIT:    
514     case XK_FALSEEXIT:   
515       switch (k2)
516         {
517         case XK_MUSTRETURNEXIT:
518         case XK_MAYRETURNEXIT:
519         case XK_MAYRETURN:
520         case XK_MUSTRETURN: return XK_MAYRETURNEXIT;
521         default:             return XK_MAYEXIT;
522         }
523       BADEXIT;
524
525     case XK_MUSTRETURN:
526       switch (k2)
527         {
528         case XK_MUSTRETURNEXIT:
529         case XK_MUSTEXIT:    return XK_MUSTRETURNEXIT;
530         case XK_MAYRETURNEXIT:
531         case XK_TRUEEXIT:
532         case XK_FALSEEXIT:
533         case XK_MAYEXIT:     return XK_MAYRETURNEXIT;
534         default:              return XK_MAYRETURN;
535         }
536       BADEXIT;
537
538     case XK_MAYRETURN:
539       if (exitkind_couldExit (k2))
540         {
541           return XK_MAYRETURNEXIT;
542         }
543       else
544         {
545           return XK_MAYRETURN;
546         }
547
548     case XK_MUSTRETURNEXIT: 
549       switch (k2)
550         {
551         case XK_MUSTRETURN:
552         case XK_MUSTEXIT:    return XK_MUSTRETURNEXIT;
553         default:              return XK_MAYRETURNEXIT;
554         }
555       BADEXIT;
556
557     case XK_MAYRETURNEXIT:   return XK_MAYRETURNEXIT;
558     case XK_GOTO:
559     case XK_MAYGOTO:         
560       if (exitkind_couldExit (k2))
561         {
562           return XK_MAYRETURNEXIT;
563         }
564       return XK_MAYGOTO;
565     }
566   
567  BADEXIT;
568 }
569
570 bool exitkind_couldExit (exitkind e)
571 {
572   switch (e)
573     {
574     case XK_MAYEXIT:
575     case XK_MUSTEXIT:
576     case XK_TRUEEXIT:
577     case XK_FALSEEXIT:
578     case XK_MAYRETURNEXIT:
579     case XK_MUSTRETURNEXIT: 
580     case XK_GOTO:
581     case XK_MAYGOTO: return TRUE;
582     default: return FALSE;
583     }
584 }
585
586 static bool exitkind_couldReturn (exitkind e) /*@*/ 
587 {
588   switch (e)
589     {
590     case XK_MUSTRETURN:
591     case XK_MAYRETURN:
592     case XK_MAYRETURNEXIT:
593     case XK_MUSTRETURNEXIT:  return TRUE;
594     default: return FALSE;
595     }
596 }
597
598 static bool exitkind_couldGoto (exitkind e) /*@*/
599 {
600   return (e == XK_GOTO || e == XK_MAYGOTO);
601 }
602
603 bool exitkind_couldEscape (exitkind e)
604 {
605   return exitkind_couldReturn (e) || exitkind_couldExit (e)
606     || exitkind_couldGoto (e);
607 }
608
609 exitkind exitkind_fromInt (int x)
610 {
611   /*@+enumint@*/
612   llassert (x >= XK_ERROR && x <= XK_LAST);
613   /*@=enumint@*/
614
615   return (exitkind) x;
616 }
617
618
619
620
621
622
623
This page took 0.125894 seconds and 5 git commands to generate.