469,327 Members | 1,242 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,327 developers. It's quick & easy.

can preprocessor automatically make N array elements?

dan
I would like to have the preprocessor automatically generate the
number of array elements requested. Each element is zero. The elements
get pasted into a larger array. The other elements may be non-zero.

***** Here is an example of what I need to do:

#define YEAR_1 2005
#define YEAR_2 2007
#define YEARS (YEAR_2 - YEAR_1 + 1)

// Start missing steps (using ## operator in some way?)
// This is the part I can't figure out.

// I think the following definitions are probably needed in the
missing steps
// I'd like ZEROES_AND_COMMAS (YEARS) to get translated to one of them

#define ZEROES_AND_COMMAS_1 0
#define ZEROES_AND_COMMAS_2 0, 0
#define ZEROES_AND_COMMAS_3 0, 0, 0

// End missing steps

#define ARRAY_ELEMS_AGE 0, 1, 5, 10, 15, 20, 40, 60
#define ARRAY_ELEMS_YRS ZEROES_AND_COMMAS (YEARS)
#define ARRAY_ELEMS_EDU 0, 6, 8, 12, 16

int intArray [] = { ARRAY_ELEMS_AGE , ARRAY_ELEMS_YRS ,
ARRAY_ELEMS_EDU , };

// intArray ends up with { 0, 1, 5, 10, 15, 20, 40, 60, 0, 0, 0,
0, 6, 8, 12, 16, }

****** Here's one failed test program (does not compile)

#include <stdio.h>
#include <stdlib.h>

#define YEAR_1 2005
#define YEAR_2 2007
#define YEARS (YEAR_2 - YEAR_1 + 1)

#define CAT(x,y) x ## y
#define XCAT(x,y) CAT(x,y)

#define ZEROES_AND_COMMAS_1 0
#define ZEROES_AND_COMMAS_2 0, 0
#define ZEROES_AND_COMMAS_3 0, 0, 0

#define ZEROES_AND_COMMAS(n) XCAT(ZEROES_AND_COMMAS_, n)

main () {
int intArray [] = { ZEROES_AND_COMMAS (YEARS) };
printf ("Number of elements = %d\n", sizeof (intArray) / sizeof
(int));
}

This would actually be useful. I'm very familiar with the C
preprocessor. I've experimented with the ## operator a lot, and can't
make it do the above task, including experiments related to K+R page
231 about using a second level of macro definition. Can anyone explain
how to solve this problem? Or get the test program to compile and
produce correct array length output?

Thanks,
Daniel Goldman

Jul 29 '07 #1
14 11529
Yes the preprocessor can generate array elemtnes along with complicated
templates:

http://groups.google.com/group/comp....382dc9a40439c7
:^0

Jul 29 '07 #2
dan said:
I would like to have the preprocessor automatically generate the
number of array elements requested. Each element is zero. The elements
get pasted into a larger array. The other elements may be non-zero.
Write, and use, a prepreprocessor. That is, write a program which takes
simple instructions from a file, and which then writes out a .h file
that suits your needs exactly. Then run the program. Then #include the
resulting .h into your code, and you're done.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jul 29 '07 #3
dan <da*******@yahoo.comwrites:
I would like to have the preprocessor automatically generate the
number of array elements requested. Each element is zero. The elements
get pasted into a larger array. The other elements may be non-zero.

***** Here is an example of what I need to do:

#define YEAR_1 2005
#define YEAR_2 2007
#define YEARS (YEAR_2 - YEAR_1 + 1)

// Start missing steps (using ## operator in some way?)
// This is the part I can't figure out.

// I think the following definitions are probably needed in the
missing steps
// I'd like ZEROES_AND_COMMAS (YEARS) to get translated to one of them

#define ZEROES_AND_COMMAS_1 0
#define ZEROES_AND_COMMAS_2 0, 0
#define ZEROES_AND_COMMAS_3 0, 0, 0

// End missing steps

#define ARRAY_ELEMS_AGE 0, 1, 5, 10, 15, 20, 40, 60
#define ARRAY_ELEMS_YRS ZEROES_AND_COMMAS (YEARS)
#define ARRAY_ELEMS_EDU 0, 6, 8, 12, 16

int intArray [] = { ARRAY_ELEMS_AGE , ARRAY_ELEMS_YRS ,
ARRAY_ELEMS_EDU , };

// intArray ends up with { 0, 1, 5, 10, 15, 20, 40, 60, 0, 0, 0,
0, 6, 8, 12, 16, }
You don't see averse to C99, going by your comment syntax, so there may
be another way:

int intArray [] = { ARRAY_ELEMS_AGE, [N_AGES+YEARS] = ARRAY_ELEMS_EDU };

You can introduce an index part way into an initialiser list. For
this work, you need to know (as a constant expression) the number of
ARRAY_ELEMS_AGE elements (or, of course, the total size and the number
of training EDU elements).

All elements not explicitly initialised are set to zero (provided
there is at least one value explicit value in the list).

--
Ben.
Jul 29 '07 #4
dan <da*******@yahoo.comwrote:
# I would like to have the preprocessor automatically generate the
# number of array elements requested. Each element is zero. The elements
# get pasted into a larger array. The other elements may be non-zero.

You can probably get (or already have) a real macro processor
like m4 or macros far superior to m4. Use those and most of
your problems will disappear. Depending on your environment
you can have tools like m4, sed, awk, etc and you can write
code the way you want to, and let the software grot it into
something the c compiler can cope with.

For example, it's simple to write a tclsh filter that converts
= to == and := to =. On systems like MacOSX, you can use textutil
to convert programs written as rtfs into plain texts.

#!/usr/bin/tclsh
while {[gets stdin line]>=0} {
puts stdout [string map {:= = = == * != ² <= ³ >= Â !} $line]
}
exit 0

It's odd that for all the advances in user interfaces in the
past forty years, most programmers are still using the tools
and forms of sixties and seventies.

--
SM Ryan http://www.rawbw.com/~wyrmwif/
OOOOOOOOOO! NAVY SEALS!
Jul 29 '07 #5
dan
On Jul 28, 11:38 pm, Richard Heathfield <r...@see.sig.invalidwrote:
dan said:
I would like to have the preprocessor automatically generate the
number of array elements requested. Each element is zero. The elements
get pasted into a larger array. The other elements may be non-zero.

Write, and use, a prepreprocessor. That is, write a program which takes
simple instructions from a file, and which then writes out a .h file
that suits your needs exactly. Then run the program. Then #include the
resulting .h into your code, and you're done.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
That's a good idea, if I could make it work in this context. USENET is
so helpful for getting suggestions, and of course the poster can never
explain all the context of a complex application. I already use a pre-
pre-processor (shell script with various unix utilities and other
commands) to auto-generate 1) function prototypes header file, and 2)
external definitions header file. It works great.

Related to your suggestion, the pre-pre-processor might either:

- Generate a file for inclusion, with the contents 0, 0, 0

OR

- Edit (using sed) some line like the following:
#define ARRAY_ELEMS_YRS 0, 0, 0

What I don't see is the format for the "simple instructions" where the
pre-pre-processor could understand them. Right now the "simple
instructions" are like the following (embedded within a header file
with about 40,000 lines):

#define YEAR_1 2005
#define YEAR_2 2007
#define YEARS (YEAR_2 - YEAR_1 + 1)

This same code is repeated many times, each time for a different data
scenario. One data set may be 1992-2006. Another may be 2000-2005. So
YEAR_1 and YEAR_2 are defined many times. Based on conditional
compilation, only one of these definitions is compiled.

I don't want to create separate files with "simple
instructions" (instead of using #define YEAR_1 #define YEAR_2). The
overhead would be more maintenance than simply hard-coding
ARRAY_ELEMS_YRS. I just want to make a change in one place (#define
YEAR_2) and everything else is automatically generated.

On further reflection... Perhaps the pre-pre-processor could do the
following:

- cpp -dM the source to generate the #define lines
- grep the conditionally compiled lines for YEAR_1 and YEAR_2
- get the values for YEAR_1 and YEAR_2
- In shell script, use while loop to build "0, 0, 0"
- sed the header file to fix up ARRAY_ELEMS_YRS

Of course, the pre-pre-processor could be invoked in the same shell
script that invokes the regular compile. You can probably tell I was
skeptical the pre-pre-processor would work in this context when I
started writing this post, and am now more optimistic. I'll give it a
try.

Am I correct to assume that you don't think the original idea (somehow
use ## within preprocessor) will work?

Thanks,
Daniel Goldman

Jul 29 '07 #6
dan said:

<snip>
You can probably tell I was
skeptical the pre-pre-processor would work in this context when I
started writing this post, and am now more optimistic. I'll give it a
try.
Glad to hear it. Not suggesting for a moment that it's trivial.
Personally, I think I'd have approached matters rather differently, but
I don't suppose you want to hear that right now, since you're so far
down this road.
Am I correct to assume that you don't think the original idea (somehow
use ## within preprocessor) will work?
I don't see how, really I don't. This kind of trick isn't really what
the pre-processor is for.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jul 29 '07 #7
dan
On Jul 29, 10:40 am, SM Ryan <wyrm...@tango-sierra-oscar-foxtrot-
tango.fake.orgwrote:
dan <dagold...@yahoo.comwrote:

# I would like to have the preprocessor automatically generate the
# number of array elements requested. Each element is zero. The elements
# get pasted into a larger array. The other elements may be non-zero.

You can probably get (or already have) a real macro processor
like m4 or macros far superior to m4. Use those and most of
your problems will disappear. Depending on your environment
you can have tools like m4, sed, awk, etc and you can write
code the way you want to, and let the software grot it into
something the c compiler can cope with.

For example, it's simple to write a tclsh filter that converts
= to == and := to =. On systems like MacOSX, you can use textutil
to convert programs written as rtfs into plain texts.

#!/usr/bin/tclsh
while {[gets stdin line]>=0} {
puts stdout [string map {:= = = == * != <= >= !} $line]}

exit 0

It's odd that for all the advances in user interfaces in the
past forty years, most programmers are still using the tools
and forms of sixties and seventies.

--
SM Ryanhttp://www.rawbw.com/~wyrmwif/
OOOOOOOOOO! NAVY SEALS!
On m4, I looked into that a while back, and decided not. I didn't "get
it". I do use other unix utilities a lot, especially sed and shell
programming.

Can m4 be used in place of cpp for serious development? Is it a good
idea? I couldn't tell from looking at the GNU m4 site or old USENET
posts.

Daniel Goldman

Jul 29 '07 #8
dan
On Jul 28, 11:25 pm, "Chris Thomasson" <cris...@comcast.netwrote:
Yes the preprocessor can generate array elemtnes along with complicated
templates:

http://groups.google.com/group/comp....browse_frm/thr...

:^0
Concerning the preprocessor generating code via recursion, I looked at
the code and didn't "get it". I'm not saying it doesn't work. Your
suggestion did make me think some more, and I came up with a pretty
simple alternative that seems to work, besides the suggestions from
others (m4, C99 designated array initializaters, pre-pre-processor).
The simple alternative doesn't use recursion or parameterization, but
just tests for each value of YEARS, which is quite manageable. The
example below shows more realistically the actual problem, in terms of
some EDU possibly not being used, so left out of the array. By the
way, the example has three variables, but there can be many tens of
variables, which is why I need to take into account which ones might
be used.

Thanks,
Daniel Goldman

#include <stdio.h>
#include <stdlib.h>

#define YES 1
#define NO 0

#define ISUSED_AGE YES
#define ISUSED_EDU NO

#define YEAR_1 2000
#define YEAR_2 2002
#define YEARS (YEAR_2 - YEAR_1 + 1)

#if ISUSED_AGE == YES
#define ELEMS_AGE 0, 1, 5, 10, 15, 20, 40, 60,
#endif

#if ISUSED_AGE == NO
#define ELEMS_AGE
#endif

#if ISUSED_EDU == YES
#define ELEMS_EDU 0, 6, 8, 12, 16,
#endif

#if ISUSED_EDU == NO
#define ELEMS_EDU
#endif

// assume year var always used

#if YEARS == 1
#define ELEMS_YRS 0,
#endif

#if YEARS == 2
#define ELEMS_YRS 0, 0,
#endif

#if YEARS == 3
#define ELEMS_YRS 0, 0, 0,
#endif

// more of these as needed

main () {
int ndx;
int elems;
int intArray [] = { ELEMS_AGE ELEMS_YRS ELEMS_EDU };

elems = sizeof (intArray) / sizeof (int);
for (ndx = 0; ndx < elems; ndx++) {
printf ("ndx = %d; el = %d\n", ndx, intArray [ndx]);
}
}

Jul 29 '07 #9
dan
On Jul 29, 11:35 am, Richard Heathfield <r...@see.sig.invalidwrote:
dan said:

<snip>
You can probably tell I was
skeptical the pre-pre-processor would work in this context when I
started writing this post, and am now more optimistic. I'll give it a
try.

Glad to hear it. Not suggesting for a moment that it's trivial.
Personally, I think I'd have approached matters rather differently, but
I don't suppose you want to hear that right now, since you're so far
down this road.
Am I correct to assume that you don't think the original idea (somehow
use ## within preprocessor) will work?

I don't see how, really I don't. This kind of trick isn't really what
the pre-processor is for.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Glad to hear it. Not suggesting for a moment that it's trivial.
Personally, I think I'd have approached matters rather differently, but
I don't suppose you want to hear that right now, since you're so far
down this road.
I don't mind other suggestions. Please let me know what you think.
Even with over 90,000 lines of header files, it's OK to make large-
scale changes because all the coding is done using vi, shell scripts,
sed, etc., and the code is very structured. I write a shell script or
use various vi commands to make big changes quickly.

Maybe you're going to suggest to do the jagged arrays as follows?

int ageIntArray [] = { 0, 5, 10 20, 40, 60};
int eduIntArray [] = { 0, 6, 8, 12, 16 };
int yrsIntArray [] = { 2000, 2001, 2002 };

int *intArrayArray [] = { ageIntArray, eduIntArray, yrsIntArray };

This is how it was previously implemented, with everything getting
filled in with cpp. It worked OK, but there were two problems:

- Had to account in code for whether EDU (or other var) was included
or not. When I needed to alphabetize or otherwise sort an array in
the code, it was "tricky". Now the array just includes the used vars,
so the code is much cleaner.

- Maintaining ageIntArray, eduIntArray, etc. as separate arrays added
a lot of header complexity. Some scenarios have 20 or more variables.
And besides "intArray" various other arrays with other attributes.
Now, instead of 20 separate arrays for intArray, I hoping for one
"jammed" array with all the used elements jammed together, and another
array that is easily set at runtime to point into the jammed array at
the right points.

Thanks,
Daniel

Jul 29 '07 #10
dan said:

<snip>
>Personally, I think I'd have approached matters rather differently,
but I don't suppose you want to hear that right now, since you're so
far down this road.

I don't mind other suggestions. Please let me know what you think.
Even with over 90,000 lines of header files, it's OK to make large-
scale changes because all the coding is done using vi, shell scripts,
sed, etc., and the code is very structured. I write a shell script or
use various vi commands to make big changes quickly.

Maybe you're going to suggest to do the jagged arrays as follows?

int ageIntArray [] = { 0, 5, 10 20, 40, 60};
int eduIntArray [] = { 0, 6, 8, 12, 16 };
int yrsIntArray [] = { 2000, 2001, 2002 };

int *intArrayArray [] = { ageIntArray, eduIntArray, yrsIntArray };
Actually, no. I was thinking rather more radically. But before I say
that, let me just remind you that C's partial initialisation rules
require implementations to use default static initialisation for the
uninitialised parts of any partly-initialised array. The default static
initialiser for int is 0. You may or may not find that information
helpful.

But no - what I was going to say was that it seems to me that age, edu,
and yrs don't really belong in the same array, because they aren't
really the same concept. If you nevertheless find that you need to
process them as if they were the same concept, it may be possible to
find an alternative data structure that still allows you to do the
processing you require in the way you require, without having this
rather strange mongrel array mixing different ideas together.

I don't know your problem domain sufficiently well to recommend a good
example, but it may be as simple as just having an array of pointers
rather than an array of ints. You were already beginning to experiment
along these lines, although you were using an array of arrays rather
than an array of pointers.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jul 29 '07 #11
dan
On Jul 29, 1:58 pm, Richard Heathfield <r...@see.sig.invalidwrote:
dan said:

<snip>
Personally, I think I'd have approached matters rather differently,
but I don't suppose you want to hear that right now, since you're so
far down this road.
I don't mind other suggestions. Please let me know what you think.
Even with over 90,000 lines of header files, it's OK to make large-
scale changes because all the coding is done using vi, shell scripts,
sed, etc., and the code is very structured. I write a shell script or
use various vi commands to make big changes quickly.
Maybe you're going to suggest to do the jagged arrays as follows?
int ageIntArray [] = { 0, 5, 10 20, 40, 60};
int eduIntArray [] = { 0, 6, 8, 12, 16 };
int yrsIntArray [] = { 2000, 2001, 2002 };
int *intArrayArray [] = { ageIntArray, eduIntArray, yrsIntArray };

Actually, no. I was thinking rather more radically. But before I say
that, let me just remind you that C's partial initialisation rules
require implementations to use default static initialisation for the
uninitialised parts of any partly-initialised array. The default static
initialiser for int is 0. You may or may not find that information
helpful.

But no - what I was going to say was that it seems to me that age, edu,
and yrs don't really belong in the same array, because they aren't
really the same concept. If you nevertheless find that you need to
process them as if they were the same concept, it may be possible to
find an alternative data structure that still allows you to do the
processing you require in the way you require, without having this
rather strange mongrel array mixing different ideas together.

I don't know your problem domain sufficiently well to recommend a good
example, but it may be as simple as just having an array of pointers
rather than an array of ints. You were already beginning to experiment
along these lines, although you were using an array of arrays rather
than an array of pointers.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Thanks for your comments. The initialization rules that set everything
to zero have not been helpful for these arrays yet, but yes, it's good
to keep in mind. It would come into play if I used the designated
initializations as suggested by Ben.

Related to age, edu, and yrs not belonging in the same array because
they are different concepts... There are a few differences, for
example year is never unknown, but otherwise I've learned from working
with them that they surprisingly ARE the same concept. Each one is
what I call a "range variable". It really makes the programming much
easier. I do a form of object-based programming in C, where the object
is one of those range variables, the object attributes are in the
arrays, the object instance is set when the array elements are
selected, and the functions automatically work the same with whatever
range variable is selected. Instead of separate sets of functions for
age, edu, and yrs (and many others), there is just one set of
functions.

I mislabelled "intArrayArray". It's should have been called
intPtrArray, because it is an array of int pointers. That's the
mechanism I was using before, which was fine, except it was awkward
dealing with the variables (objects) that weren't used. I agree the
array missing age, edu, and yrs is a mongrel, but I think it's a well-
behaved one.

Thanks,
Daniel Goldman

Jul 29 '07 #12
dan <da*******@yahoo.comwrites:
On Jul 29, 4:45 am, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
>dan <dagold...@yahoo.comwrites:
I would like to have the preprocessor automatically generate the
number of array elements requested. Each element is zero. The elements
get pasted into a larger array. The other elements may be non-zero.
<program outline snipped>
>>
You don't seem averse to C99, going by your comment syntax, so there may
be another way:

int intArray [] = { ARRAY_ELEMS_AGE, [N_AGES+YEARS] = ARRAY_ELEMS_EDU };

You can introduce an index part way into an initialiser list.
<snip>
I was not familiar with designated initializers, which does solve my
test case. I need to go through all of C99. Do you think the pre-
processor may not be able to do what I want, because I think I still
may need the preprocessor solution.
OK, I was just providing more data points.
The designated initializers may not work within the context of the
other code, which I felt was too involved to explain in the initial
post.
<more details snipped>
I hope this makes some sense.
Yes, but sadly the devil is in the detail so there is not way to tell
if you are into a winner here or if the CPP solution will fail at the
last (possibly as yet unseen) hurdle.

That alone would make me wary. It is never wise to work at the very
edge of what your tools can do. I think you may be better off
switching tools.

I am not a fan on complex CPP coding, mainly because the results seem
fragile and hard to maintain. YMMV.

--
Ben.
Jul 29 '07 #13
dan
On Jul 29, 3:33 pm, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
dan <dagold...@yahoo.comwrites:
On Jul 29, 4:45 am, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
dan <dagold...@yahoo.comwrites:
I would like to have the preprocessor automatically generate the
number of array elements requested. Each element is zero. The elements
get pasted into a larger array. The other elements may be non-zero.

<program outline snipped>
You don't seem averse to C99, going by your comment syntax, so there may
be another way:
int intArray [] = { ARRAY_ELEMS_AGE, [N_AGES+YEARS] = ARRAY_ELEMS_EDU };
You can introduce an index part way into an initialiser list.
<snip>
I was not familiar with designated initializers, which does solve my
test case. I need to go through all of C99. Do you think the pre-
processor may not be able to do what I want, because I think I still
may need the preprocessor solution.

OK, I was just providing more data points.
The designated initializers may not work within the context of the
other code, which I felt was too involved to explain in the initial
post.

<more details snipped>
I hope this makes some sense.

Yes, but sadly the devil is in the detail so there is not way to tell
if you are into a winner here or if the CPP solution will fail at the
last (possibly as yet unseen) hurdle.

That alone would make me wary. It is never wise to work at the very
edge of what your tools can do. I think you may be better off
switching tools.

I am not a fan on complex CPP coding, mainly because the results seem
fragile and hard to maintain. YMMV.

--
Ben.
You're right, I'm working kind of on the edge, which is dangerous. But
I'm not sure I have a choice. I have faith in C and the cpp and have
never failed to accomplish what was needed, because C is so
programmable. But there's always a first time. I'll know in a few
days. If it fails at an unseen hurdle, I'll go back to old version. In
any case, I'm not sure which tool I would switch to that would better
handle these problems. The problems are imposed by writing a framework
that handles multiple data analysis scenarios and can be compiled to
produce many separate executables, each one customized for a data
scenario and a different runtime environment. I am trying to make the
cpp code as simple to read and maintain as I can. Thanks to you and
other for providing the helpful advice.

Daniel Goldman

Jul 30 '07 #14
dan <da*******@yahoo.comwrote:

# On m4, I looked into that a while back, and decided not. I didn't "get
# it". I do use other unix utilities a lot, especially sed and shell
# programming.

m4 has a number of unnecessary problems, but it is a complete
programming language, and it can do a lot more than cpp.

# Can m4 be used in place of cpp for serious development? Is it a good
# idea? I couldn't tell from looking at the GNU m4 site or old USENET
# posts.

Depends on the build system. Makefiles have no problem inserting
an m4 step, creating .c or .i files; other more advanced systems
can be less flexible.

There are better tools than cpp; people need not bash their faces
against the wall unless it gives them pleasure.

--
SM Ryan http://www.rawbw.com/~wyrmwif/
You face forward, or you face the possibility of shock and damage.
Jul 30 '07 #15

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

205 posts views Thread by Jeremy Siek | last post: by
24 posts views Thread by Nudge | last post: by
18 posts views Thread by /* frank */ | last post: by
4 posts views Thread by Klaas Vantournhout | last post: by
25 posts views Thread by Gernot Frisch | last post: by
2 posts views Thread by =?Utf-8?B?bWFyaw==?= | last post: by
31 posts views Thread by Sam of California | last post: by
1 post views Thread by Peter Ammon | last post: by
1 post views Thread by CARIGAR | last post: by
reply views Thread by suresh191 | last post: by
reply views Thread by listenups61195 | last post: by
reply views Thread by Purva khokhar | last post: by
reply views Thread by haryvincent176 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.