manipulate fd underlying stream

Discussion in 'C Programming' started by John Kelly, Jul 31, 2010.

  1. John Kelly

    John Kelly Guest

    comp.lang.c FAQ 12.33 says:

    >Q: How can I redirect stdin or stdout to a file from within a program?


    >A: Use freopen. If you're calling a function f() which writes to stdout,
    >and you want to send its output to a file, and you don't have the option
    >of rewriting f, you can use a sequence like:
    >
    > freopen(file, "w", stdout);
    > f();
    >


    Hmmm ...


    >See, however, question 12.34.


    >Question 12.34


    >Q: Once I've used freopen, how can I get the original stdout (or stdin) back?


    >A: There isn't a good way. If you need to switch back, the best solution is not
    >to have used freopen in the first place.



    Why not leave the stream unchanged, and manipulate its underlying file
    descriptor:

    a) fflush() the stdio stream
    b) dup the stdio fd to an unused fd, saving a copy of it.
    c) close the stdio fd
    d) use open() to get an fd for the desired file, and compare the fd
    number to STDIN_FILENO or STDOUT_FILENO, as appropriate, to be sure
    it matches; if not, use dup2() to copy it to the stdio fd
    e) when done, use dup2() to copy the saved fd back to the stdio fd



    --
    Web mail, POP3, and SMTP
    http://www.beewyz.com/freeaccounts.php
    John Kelly, Jul 31, 2010
    #1
    1. Advertising

  2. John Kelly

    Ian Collins Guest

    On 07/31/10 12:56 PM, John Kelly wrote:
    >
    > comp.lang.c FAQ 12.33 says:
    >
    >> Q: How can I redirect stdin or stdout to a file from within a program?

    >
    >> A: Use freopen. If you're calling a function f() which writes to stdout,
    >> and you want to send its output to a file, and you don't have the option
    >> of rewriting f, you can use a sequence like:
    >>
    >> freopen(file, "w", stdout);
    >> f();
    >>

    >
    > Hmmm ...
    >
    >
    >> See, however, question 12.34.

    >
    >> Question 12.34

    >
    >> Q: Once I've used freopen, how can I get the original stdout (or stdin) back?

    >
    >> A: There isn't a good way. If you need to switch back, the best solution is not
    >> to have used freopen in the first place.

    >
    >
    > Why not leave the stream unchanged, and manipulate its underlying file
    > descriptor:


    Because there isn't a standard way of doing that.

    > a) fflush() the stdio stream
    > b) dup the stdio fd to an unused fd, saving a copy of it.


    That assumes dup().

    --
    Ian Collins
    Ian Collins, Jul 31, 2010
    #2
    1. Advertising

  3. John Kelly

    Eric Sosman Guest

    On 7/30/2010 8:56 PM, John Kelly wrote:
    >
    > comp.lang.c FAQ 12.33 says:
    >
    >> Q: How can I redirect stdin or stdout to a file from within a program?

    >
    >> A: Use freopen. If you're calling a function f() which writes to stdout,
    >> and you want to send its output to a file, and you don't have the option
    >> of rewriting f, you can use a sequence like:
    >>
    >> freopen(file, "w", stdout);
    >> f();

    >
    > Hmmm ...
    >
    >> See, however, question 12.34.

    >
    >> Question 12.34

    >
    >> Q: Once I've used freopen, how can I get the original stdout (or stdin) back?

    >
    >> A: There isn't a good way. If you need to switch back, the best solution is not
    >> to have used freopen in the first place.

    >
    >
    > Why not leave the stream unchanged, and manipulate its underlying file
    > descriptor:


    "File descriptoer?" What's a "file descriptor?"

    > a) fflush() the stdio stream
    > b) dup the stdio fd to an unused fd, saving a copy of it.


    What do you mean, "dup?"

    > c) close the stdio fd


    "Close?" What's that?

    > d) use open() to get an fd for the desired file, and compare the fd
    > number to STDIN_FILENO or STDOUT_FILENO, as appropriate, to be sure


    What's "open?" And what are these strange, all-caps things
    that sort of look like they might be macros?

    > it matches; if not, use dup2() to copy it to the stdio fd
    > e) when done, use dup2() to copy the saved fd back to the stdio fd


    "Dup2?" Hunh?

    In short, you're assuming (1) a specific kind of host system,
    and (2) a whole lot about the way C streams are implemented on that
    system. In CS-speak, you are writing to the implementation rather
    than to the interface.

    I recall dealing with some code that tried to mix-'n-match C's
    streams with POSIX primitives: It would fread() from a file until it
    came to something it knew would be a blob, then it did an lseek() to
    the fseek() position to synchronize the two current offsets, then
    it slurped the blob with read() "because it's more efficient," then
    did an fseek() to the lseek() spot to re-synchronize. Clever, clever,
    clever -- and utterly hopeless on VMS, the platform I was porting to.
    Dirtbag code with a dirtbag outcome.

    --
    Eric Sosman
    lid
    Eric Sosman, Jul 31, 2010
    #3
  4. John Kelly

    John Kelly Guest

    On Fri, 30 Jul 2010 21:20:03 -0400, Eric Sosman
    <> wrote:

    > In short, you're assuming (1) a specific kind of host system,
    >and (2) a whole lot about the way C streams are implemented on that
    >system. In CS-speak, you are writing to the implementation rather
    >than to the interface.


    I think of a dominant implementation as a virtual interface.


    > I recall dealing with some code that tried to mix-'n-match C's
    >streams with POSIX primitives: It would fread() from a file until it
    >came to something it knew would be a blob, then it did an lseek() to
    >the fseek() position to synchronize the two current offsets, then
    >it slurped the blob with read() "because it's more efficient," then
    >did an fseek() to the lseek() spot to re-synchronize. Clever, clever,
    >clever -- and utterly hopeless on VMS, the platform I was porting to.
    >Dirtbag code with a dirtbag outcome.


    VMS? What's that?



    --
    Web mail, POP3, and SMTP
    http://www.beewyz.com/freeaccounts.php
    John Kelly, Jul 31, 2010
    #4
  5. John Kelly

    Eric Sosman Guest

    On 7/30/2010 9:40 PM, John Kelly wrote:
    > [...]
    > VMS? What's that?


    Touché.

    --
    Eric Sosman
    lid
    Eric Sosman, Jul 31, 2010
    #5
  6. John Kelly

    Ian Collins Guest

    On 07/31/10 01:40 PM, John Kelly wrote:
    > On Fri, 30 Jul 2010 21:20:03 -0400, Eric Sosman
    > <> wrote:
    >
    >> In short, you're assuming (1) a specific kind of host system,
    >> and (2) a whole lot about the way C streams are implemented on that
    >> system. In CS-speak, you are writing to the implementation rather
    >> than to the interface.

    >
    > I think of a dominant implementation as a virtual interface.


    You can't invent a dominant implementation.

    --
    Ian Collins
    Ian Collins, Jul 31, 2010
    #6
  7. John Kelly

    Tim Harig Guest

    On 2010-07-31, John Kelly <> wrote:
    >>See, however, question 12.34.

    >
    >>Question 12.34

    >
    >>Q: Once I've used freopen, how can I get the original stdout (or stdin) back?

    >
    >>A: There isn't a good way. If you need to switch back, the best solution is not
    >>to have used freopen in the first place.

    >
    > Why not leave the stream unchanged, and manipulate its underlying file
    > descriptor:
    >
    > a) fflush() the stdio stream
    > b) dup the stdio fd to an unused fd, saving a copy of it.
    > c) close the stdio fd
    > d) use open() to get an fd for the desired file, and compare the fd
    > number to STDIN_FILENO or STDOUT_FILENO, as appropriate, to be sure
    > it matches; if not, use dup2() to copy it to the stdio fd
    > e) when done, use dup2() to copy the saved fd back to the stdio fd


    As others have pointed out, this is POSIX specific and you will probably
    get better advice from comp.unix.programming.

    Looking at the man page for dup on Linux, I don't see anything that
    explicitly prevents you from copying the file descriptor and copying it
    back; but, that doesn't mean there might not be implementation bugs on some
    platform that make it an unwise choice to use.

    Personally, I don't understand why you would bother going through all of
    that trouble instead of just leaving stdin alone and using fprinf()
    explicitly. Then there is never any confusion about where stdin points at
    any given time.
    Tim Harig, Jul 31, 2010
    #7
  8. John Kelly

    John Kelly Guest

    On Sat, 31 Jul 2010 02:54:08 +0000 (UTC), Tim Harig <>
    wrote:

    >On 2010-07-31, John Kelly <> wrote:


    >> Why not leave the stream unchanged, and manipulate its underlying file
    >> descriptor:
    >>
    >> a) fflush() the stdio stream
    >> b) dup the stdio fd to an unused fd, saving a copy of it.
    >> c) close the stdio fd
    >> d) use open() to get an fd for the desired file, and compare the fd
    >> number to STDIN_FILENO or STDOUT_FILENO, as appropriate, to be sure
    >> it matches; if not, use dup2() to copy it to the stdio fd
    >> e) when done, use dup2() to copy the saved fd back to the stdio fd

    >
    >As others have pointed out, this is POSIX specific and you will probably
    >get better advice from comp.unix.programming.
    >
    >Looking at the man page for dup on Linux, I don't see anything that
    >explicitly prevents you from copying the file descriptor and copying it
    >back; but, that doesn't mean there might not be implementation bugs on some
    >platform that make it an unwise choice to use.


    I've not experienced any problems on Linux.


    >Personally, I don't understand why you would bother going through all of
    >that trouble instead of just leaving stdin alone and using fprinf()
    >explicitly. Then there is never any confusion about where stdin points at
    >any given time.


    Maybe I have generic code that uses stdin/stdout, and the caller wants
    to manipulate fds and point them somewhere else.



    --
    Web mail, POP3, and SMTP
    http://www.beewyz.com/freeaccounts.php
    John Kelly, Jul 31, 2010
    #8
  9. John Kelly

    John Kelly Guest

    On Sat, 31 Jul 2010 05:06:01 +0100, Richard Heathfield
    <> wrote:

    >Tim Harig wrote:
    >> On 2010-07-31, John Kelly <> wrote:

    ><snip>
    >
    >>> e) when done, use dup2() to copy the saved fd back to the stdio fd

    >>
    >> As others have pointed out, this is POSIX specific and you will probably
    >> get better advice from comp.unix.programming.

    >
    >Just a note for the files - it's actually comp.unix.programmer that he
    >needs. AFAIK, comp.unix.programming is a myth.


    No POSIX on Windows?


    --
    Web mail, POP3, and SMTP
    http://www.beewyz.com/freeaccounts.php
    John Kelly, Jul 31, 2010
    #9
  10. John Kelly

    ralph Guest

    On Sat, 31 Jul 2010 04:31:01 +0000, John Kelly <>
    wrote:

    >On Sat, 31 Jul 2010 05:06:01 +0100, Richard Heathfield
    ><> wrote:
    >
    >>Tim Harig wrote:
    >>> On 2010-07-31, John Kelly <> wrote:

    >><snip>
    >>
    >>>> e) when done, use dup2() to copy the saved fd back to the stdio fd
    >>>
    >>> As others have pointed out, this is POSIX specific and you will probably
    >>> get better advice from comp.unix.programming.

    >>
    >>Just a note for the files - it's actually comp.unix.programmer that he
    >>needs. AFAIK, comp.unix.programming is a myth.

    >
    >No POSIX on Windows?


    Too ways to look at this ...
    1) Windows NT and Windows 2000 O/S did support a POSIX subsystem.
    Windows XP and later do not.
    2) The more popular C compilers for Windows still support POSIX to
    some degree or the other.
    The VC++ compiler* still supports POSIX, but it is considered
    "deprecated". Details can be found in the help files.

    [*as of VC 2008, not sure about the 2010 release.]

    Microsoft O/S and compilers only support POSIX 1003.1 which was
    earlier than even current versions available at the time, and thus
    limited in POSIX services, as well as denied access to many Windows
    services.

    So the answer to your question is technically 'yes' for some versions
    of Windows and very simple applications, but generally 'no' for use as
    a migration or cross-platform tool.

    -ralph
    ralph, Jul 31, 2010
    #10
  11. John Kelly

    John Kelly Guest

    On Sat, 31 Jul 2010 05:43:34 +0100, Richard Heathfield
    <> wrote:

    >John Kelly wrote:


    >> No POSIX on Windows?


    >Yes, Windows has POSIX (kinda)


    Kinda like this?

    http://www.suacommunity.com/SUA.aspx


    >you'll get better discussions on POSIX in a Unix programming group
    >than in a Windows programming group


    Do you want to shoo away Linux C programmers from c.l.c?


    --
    Web mail, POP3, and SMTP
    http://www.beewyz.com/freeaccounts.php
    John Kelly, Jul 31, 2010
    #11
  12. John Kelly

    Shao Miller Guest

    On Jul 31, 1:05 am, ralph <> wrote:
    > 1) Windows NT and Windows 2000 O/S did support a POSIX subsystem.
    > Windows XP and later do not.

    There is a computer at my office running XP with the MS-bought
    Interix. Even later Windows versions have POSIX subsystems. POSIX is
    thus supported, but not built-in, perhaps.

    http://en.wikipedia.org/wiki/Interix
    Shao Miller, Jul 31, 2010
    #12
  13. John Kelly

    John Kelly Guest

    On Sat, 31 Jul 2010 00:05:45 -0500, ralph <>
    wrote:

    >On Sat, 31 Jul 2010 04:31:01 +0000, John Kelly <>
    >wrote:
    >
    >>On Sat, 31 Jul 2010 05:06:01 +0100, Richard Heathfield
    >><> wrote:
    >>
    >>>Tim Harig wrote:
    >>>> On 2010-07-31, John Kelly <> wrote:
    >>><snip>
    >>>
    >>>>> e) when done, use dup2() to copy the saved fd back to the stdio fd
    >>>>
    >>>> As others have pointed out, this is POSIX specific and you will probably
    >>>> get better advice from comp.unix.programming.
    >>>
    >>>Just a note for the files - it's actually comp.unix.programmer that he
    >>>needs. AFAIK, comp.unix.programming is a myth.

    >>
    >>No POSIX on Windows?

    >
    >Too ways to look at this ...
    >1) Windows NT and Windows 2000 O/S did support a POSIX subsystem.
    >Windows XP and later do not.


    What's this:

    Step 1: Turning on the SUA features
    The Subsystem for Unix-based Applications (SUA) is part of the Windows
    OS distribution. Installing the subsystem requires no additional CD or
    download. It's a component/feature of the base distribution of Windows
    Server 2008, Windows Server 2008/R2, Windows Server 2003 R2, Windows 7
    and Windows Vista Ultimate & Enterprise. All you need to do is turn the
    feature on.

    http://www.suacommunity.com/SUA.aspx



    >So the answer to your question is technically 'yes' for some versions
    >of Windows and very simple applications, but generally 'no' for use as
    >a migration or cross-platform tool.



    Step 2: Installing the Utilities and SDK for Unix-based Applications
    Once the SUA "feature" is turned on, the next step is to download the
    Utilities and SDK. From the Start menu, under All Programs then under
    Subsystem for Unix-based Applications you can find the link to download
    the Utilities and SDK from the Microsoft website. Alternatively, you
    can visit the download site directly: Installing and Using Utilities and
    SDK for Unix-based Applications. This page is important as it outlines
    the difference between a standard (default) installation and a custom
    install.

    Note: A common pitfall is to just accept the default installation. The
    default install does not include the GNU utilities and GNU SDK.

    Note: We recommend for a Windows systems that the installation happen as
    the Local Administrator (not as a user in the Administrators Group).


    --
    Web mail, POP3, and SMTP
    http://www.beewyz.com/freeaccounts.php
    John Kelly, Jul 31, 2010
    #13
  14. John Kelly

    Seebs Guest

    On 2010-07-31, John Kelly <> wrote:
    > Do you want to shoo away Linux C programmers from c.l.c?


    Not likely -- my day job is about 98% Linux these days. But I generally
    don't talk about the POSIX-specific stuff here, because that's not
    related to C. With a few exceptions (and admittedly, I actually
    work with those exceptions a fair bit!), the POSIX stuff I do is
    language-agnostic, and you could ask the same questions, and get the
    same answers, when talking about perl or Ruby programs that were
    working with the POSIX interfaces.

    I think the big thing people are pursuing in trying to direct
    people to other newsgroups is to maximize discussion quality and
    value. If you ask POSIX questions here, there are two likely
    problems:

    1. The discussion will be at best totally uninteresting to a large
    number of readers. This makes the group less valuable to them and
    might cause them to leave -- but there are some very serious C experts
    who happen to mostly not be using Unix.

    2. The discussion will pick up a lot of things said by people who
    aren't that interested in or good at POSIX, and who as a result don't
    really know what they're talking about -- but the real POSIX experts
    are mostly not here, or not here with intent to talk about POSIX.

    So if instead those questions are asked in a group more specific
    to the environment they apply in, everyone gets a better newsgroup
    experience, and the questions get better answers -- which are seen
    by people more interested in those answers.

    Long story short, it seems that, as long as there's enough traffic
    to justify multiple newsgroups, everyone seems to win when those
    newsgroups keep to their topics, and separation of topics is observed.

    (And keep in mind, I'm writing this from the perspective of someone
    who has written some code which does stuff like "intercept underlying
    file operations and manipulate the values apparently returned by
    the library." I know more about what happens in several common C
    libraries when you start messing around with file descriptors than
    anyone but a library maintainer is ever likely to have reason to
    know; I just don't think it's topical here.)

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    Seebs, Jul 31, 2010
    #14
  15. John Kelly

    ralph Guest

    On Sat, 31 Jul 2010 05:19:49 +0000, John Kelly <>
    wrote:


    >
    >What's this:
    >
    >Step 1: Turning on the SUA features
    >The Subsystem for Unix-based Applications (SUA) is part of the Windows
    >OS distribution. Installing the subsystem requires no additional CD or
    >download. It's a component/feature of the base distribution of Windows
    >Server 2008, Windows Server 2008/R2, Windows Server 2003 R2, Windows 7
    >and Windows Vista Ultimate & Enterprise. All you need to do is turn the
    >feature on.
    >
    >http://www.suacommunity.com/SUA.aspx
    >
    >
    >
    >Step 2: Installing the Utilities and SDK for Unix-based Applications
    >Once the SUA "feature" is turned on, the next step is to download the
    >Utilities and SDK. ...


    LOL

    I knew I'd be in trouble the second I hit the return.

    I didn't mention SUA/Interix as I was under the impression that
    SUA/Interix was not fully POSIX complaint. That apparently is not
    true.
    ralph, Jul 31, 2010
    #15
  16. In article <>,
    John Kelly <> wrote a bunch of good stuff, as he
    usually does:
    ....
    >Do you want to shoo away Linux C programmers from c.l.c?


    Obviously, yes. Their whole goal is to shoo everyone away, so that they
    can do their collective jerk-off over the Almight C Standards document.

    I assumed you understood that by now.

    --
    "We should always be disposed to believe that which appears to us to be
    white is really black, if the hierarchy of the church so decides."

    - Saint Ignatius Loyola (1491-1556) Founder of the Jesuit Order -
    Kenny McCormack, Jul 31, 2010
    #16
  17. John Kelly

    John Kelly Guest

    On Sat, 31 Jul 2010 13:10:24 +0000 (UTC),
    (Kenny McCormack) wrote:

    >In article <>,
    >John Kelly <> wrote a bunch of good stuff, as he
    >usually does:


    >>Do you want to shoo away Linux C programmers from c.l.c?


    >Obviously, yes. Their whole goal is to shoo everyone away, so that they
    >can do their collective jerk-off over the Almight C Standards document.


    comp.std.c appears to be alive


    >I assumed you understood that by now.


    Code is more fun than standards.



    --
    Web mail, POP3, and SMTP
    http://www.beewyz.com/freeaccounts.php
    John Kelly, Jul 31, 2010
    #17
  18. On Jul 31, 8:20 am, Eric Sosman <> wrote:
    >      "File descriptoer?"  What's a "file descriptor?"
    >      What do you mean, "dup?"
    >      "Close?"  What's that?
    >      What's "open?"  And what are these strange, all-caps things
    >      "Dup2?"  Hunh?


    I'm not sure to what extent Mr. Sosman seeks to edify and
    to what extent he seeks to amuse, but I don't think I'm alone
    in saying that programming for a non-Unix system has no
    conceivable purpose in the ivory tower. Non-Unix programmers have
    some other purpose: avarice for filthy lucre, writing viruses,
    etc.

    In a newsgroup on restaurants we wouldn't be condemned if we
    assumed OP is not some villain serving rat poison to customers.
    Why then, in a C programming forum, do we ask why OP isn't some
    sado-masochist programming a system without open() and close()?

    James Dow Allen
    James Dow Allen, Jul 31, 2010
    #18
  19. In article <>,
    John Kelly <> wrote:
    >On Sat, 31 Jul 2010 13:10:24 +0000 (UTC),
    >(Kenny McCormack) wrote:
    >
    >>In article <>,
    >>John Kelly <> wrote a bunch of good stuff, as he
    >>usually does:

    >
    >>>Do you want to shoo away Linux C programmers from c.l.c?

    >
    >>Obviously, yes. Their whole goal is to shoo everyone away, so that they
    >>can do their collective jerk-off over the Almight C Standards document.

    >
    >comp.std.c appears to be alive


    But, no, they won't stay there.

    >>I assumed you understood that by now.

    >
    >Code is more fun than standards.


    Not to these jerkoffs.

    And this is probably as good a time as any for me to re-iterate a point
    I've made many times before. These people are actually almost all old
    Unix hands and they are perfectly comfortable with Unix-isms (like
    read() and write()). Normally, there'd be no problem discussing Unix-y
    things here, but the problem is that when, in the early 90s, the Unix
    guys saw the world going MS and Windows (sorry, guys, but it is true),
    they went apeshit and they realized that their beloved newsgroups (and
    specifically CLC) were about to go all "lpParm" on them and they
    couldn't stand that.

    So, they concocoted this "What's in the standard and only what's in the
    standard" nonsense and made a pact to stand by it. Part of that pact
    was that they had to pretend not to understand or know anything about
    the Unix-y stuff (or any other so-called "system specific" stuff). That
    was the price paid to ward off the evils of "lpParm".

    (And yes, just in case it isn't clear to the numskulls, I'm using
    "lpParm" as a metaphor for all the Windows-y stuff. The stuff that
    drives these guys to madness...)

    --
    Just for a change of pace, this sig is *not* an obscure reference to
    comp.lang.c...
    Kenny McCormack, Jul 31, 2010
    #19
  20. John Kelly

    John Kelly Guest

    On Sat, 31 Jul 2010 15:02:31 +0000 (UTC),
    (Kenny McCormack) wrote:

    >In article <>,
    >John Kelly <> wrote:
    >
    >>Code is more fun than standards.

    >
    >Not to these jerkoffs.
    >
    >And this is probably as good a time as any for me to re-iterate a point
    >I've made many times before. These people are actually almost all old
    >Unix hands and they are perfectly comfortable with Unix-isms (like
    >read() and write()). Normally, there'd be no problem discussing Unix-y
    >things here, but the problem is that when, in the early 90s, the Unix
    >guys saw the world going MS and Windows (sorry, guys, but it is true),
    >they went apeshit


    For Windows XP:

    a) download Windows Services for UNIX Version 3.5
    http://www.microsoft.com/downloads/...88-601b-44f1-81a4-02878ff11778&displaylang=en

    b) get hotfixes and apply
    http://www.rockbox.org/wiki/InterixDevelopment

    c) add complete toolset from sua community site
    http://www.suacommunity.com/SUA.aspx
    ftp://ftp.interopsystems.com/pkgs/bundles/pkg-current-bundlecomplete35.exe


    Looks POSIXy to me ...



    --
    Web mail, POP3, and SMTP
    http://www.beewyz.com/freeaccounts.php
    John Kelly, Jul 31, 2010
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Dave
    Replies:
    1
    Views:
    313
    Mike Wahler
    Jan 22, 2005
  2. Rasmusson, Lars
    Replies:
    1
    Views:
    712
    popov
    Apr 30, 2004
  3. Replies:
    5
    Views:
    587
  4. Replies:
    9
    Views:
    612
    Alex Buell
    Apr 27, 2006
  5. Xiao Ma
    Replies:
    16
    Views:
    1,404
    =?ISO-8859-15?Q?Arne_Vajh=F8j?=
    Oct 27, 2007
Loading...

Share This Page