The Characters in the String Go Round and Round

Python 2, 95 bytes

s,m,n=input()
print s[:n]
for i in range(m-2):print s[~i]+' '*(n-2)+s[n+i]
print s[1-m::-1][:n]

Prints the first line, then the two vertical lines, then the last line.

There's got to be something shorter than writing print three times, but everything I've tried so far with saving to a variable and '\n'.join has been longer.


Pyth, 47 46 45 40 37 36 bytes

This is the obvious approach implemented in Pyth. It prints the first line by indexing 0:width and then the middle, then the end.

Thanks to @Jakube for the tip with using z and Q for two inputs and using p.

AkYQ<zkV-Y2p*d-k2@zt_N@z+kN;<_<z-2Yk

Takes input from stdin as a string and as a tuple of dimensions, newline separated:

Hello, World! 
5, 4

and writes to stdout.

Try it here.

A              Double assignment
 kY            The vars k and Y
 Q             The dimension tuple
<zk            Prints out first line by doing z[:width]
V-Y2           For N in height-2
 p             Print out everything
  *d           Repeat " "
   -k2         Width-2 times
  @z           Index z
   -_N1        At index -N-1
  @z           Index z
   +kN         At index k+N
;              Close out loop
<_<z-2Yk       Print last line

CJam, 31 30 bytes

At Optimizer's insistence, here is my own attempt. I'm not a fan of winning my own challenges, so I'm counting the APL family (or someone better at CJam) to beat this. ;)

l~:H;:V/(N@s{)V2-S*@(N@}H2-*W%

Takes input in the same order as given in the question:

"Hello, World! " 5 4

Test it here.

One byte saved thanks to Optimizer.

Explanation

Originally, I had a really nice idea for starting with the rectangle of spaces and then literally wrapping the string around it while rotating the entire grid four times. However, I couldn't seem to get that to work in case where width or height or both are 2. So I tried the naive approach (print top, loop over sides, print bottom), and surprisingly it turned out to be really short.

l~                             "Read and evaluate the input.";
  :H;                          "Store the height in H and discard it.";
     :V/                       "Store the width in V and split the input into chunks of size V.";
        (N                     "Slice off the first such chunk and push a newline.";
          @s                   "Pull up the other chunks and join them back together.";
            {          }H2-*   "Repeat this block H-2 times, printing the sides.";
             )                 "Slice off the last character of the string.";
              V2-S*            "Push V-2 spaces.";
                   @(          "Pull up the remaining string and slice off the first character.";
                     N@        "Push a newline and pull up the remaining string.";
                            W% "Reverse the remainder of the string, which is the bottom row.";