Lipogram "quine"

CJam, 45 41 38 35 bytes

{`"OX$_?"+_l&{{H)+`}/"\He,}":)}&}_~

If the input character is none of the characters "$&)+,/:?HOX\_`el{}, this program prints the following, slightly modified version of itself. Try it online!

{`"OX$_?"+_l&{{H)+`}/"\He,}":)}&}OX$_?

Otherwise, the program prints the following, obfuscated version of the modification. Try it online!

''r'4'a'j'6'q'Q'4'='q'~'8'''Z';'='r''A'4'n'Z'w'>''4'L';''8''a'j'6'q'Q]If-~

Note that some of the characters are unprintable. Try it online!

How it works

{`"OX$_?"+_l&{{H)+`}/"\He,}":)}&}_~

{                               }    Define a code block.
                                 _~  Push a copy and execute the copy.
 `                                   Push a string representation of the block.
  "OX$_?"                            Push that string.
         +_                          Concatenate and push a copy.
           l&                        Intersect the copy with the input.
             {                }&     If the intersection is non-empty:
              {    }/                  For each character of the concat. strings:
               H)                        Push 18.
                 +                       Add it to the character.
                  `                      Inspect; turn 'c into "'c".
                     "He,}"            Push that string.
                           :)          Increment each char. Pushes "If-~"

In the first possible output program, we avoid using ~ to be able to use it in the other program. Therefore, instead of _~, the modified program ends with OX$_?, which works as follows.

O        Push "" (falsy).
 X$      Push a copy of the code block.
   _     Push yet another copy.
    ?    Ternary if; since "" is falsy, execute the second copy.

Finally, in the remaining output program,

''r'4'a'j'6'q'Q'4'='q'~'8'''Z';'='r''A'4'n'Z'w'>''4'L';''8''a'j'6'q'Q]

wraps all those characters in an array, therefore pushing the following string.

"'4aj6qQ4=q~8'Z;=r'104nZw>'4L;'8'j6qQ"

If- subtracts 18 from each character code, pushing the string

"{`\"OX$_?\"+_l&{{H)+`}/\"\He,}\":)}&}OX$_?"

which ~ the evaluates.


JavaScript (ES6), 356 340 327 308 303 263

Now using Function`...``` for the second program:

f=(b=y=>[for(x of`f=${f};f()`)x.charCodeAt().toString(y).toUpperCase()])=>alert([`eval('\\${b(8).join('\\')}')`,`eval(String.fromCharCode(${b(10).map(x=>'+9-8'.repeat(x))}))`,'Function`\\x'+b(16).join('\\x')+'```'][1+"0e1v2a3l4(5'6'7)\\".indexOf(prompt())%2]);f()

The function packs itself into one of three possible programs:

  1. The first program calls eval on a string literal containing the function's code with each character escaped as an octal value.

    eval('\146\165...')
  2. The second program redirects the browser to a javascript: URL containing the function's code with each character URL encoded. This is the only way I could think to evaluate code without using parentheses. It also escapes the letters in 'eval'.

    window["\x6coc\x61tion"]["hr\x65f"]="j\x61\x76\x61script:%66%75..."
  3. The last program is painfully long. It builds the function's code by adding one (+9-8) at a time to get each character code. This is to avoid using the octal digits.

    eval(String.fromCharCode(+9-8+9-8+9-8+9-8...))

The correct program is indexed by searching a carefully constructed string for the input character:

[`program_1`,`program_3`,`program_2`][1+"0e1v2a3l4(5'6'7)\\".indexOf(prompt())%2]

Here's an ungolfed, untested version. It might not work because of newlines in the source.

function f() {
    // convert source code of current function to bytes
    var bytes = Array.map(f + 'f()', x => x.charCodeAt());

    // pack this function's code in one of three possible programs,
    // depending on the input
    var input = prompt();

    // PROGRAM 1 - only contains characters: eval(')01234567\
    // eval('\146\165...')
    var source = "eval('\\" + bytes.map(x => x.toString(8)).join('\\') + "')";

    // PROGRAM 2 - doesn't contain characters: eval('')
    // window["\x6coc\x61tion"]["hr\x65f"]="j\x61\x76\x61script:%66%75..."
    // -> window["location"]["href"] = "javascript:..."
    if ("eval(')".includes(input)) {
        source = 'window["\\x6coc\\x61tion"]["hr\\x65f"]="j\\x61\\x76\\x61script:%';
        source += bytes.map(x => x.toString(16).toUpperCase()).join('%') + '"';
    }

    // PROGRAM 3 - doesn't contain characters: 01234567\
    // eval(String.fromCharCode(+9-8+9-8+9-8+9-8...))
    if ('01234567\\'.includes(input)) {
        source = "eval(String.fromCharCode(";
        source += bytes.map(x => '+9-8'.repeat(x)).join(',') + '))';
    }

    console.log(source);
}
f()