- HMAC-SHA-xxx has an output length of xxx bits
That's right, the output of the HMAC function is identical to the output of the hash by default. This is obvious if you take the design of HMAC in consideration.
- HMAC-SHA-xxx-yyy has an output length of yyy bits
Certainly. It has been defined that way in the venerable RFC 2104 - HMAC: Keyed-Hashing for Message Authentication, section 5: Truncated output.
Not many implementations will allow you to specify the output size, so you may have to truncate yourself. Beware that it is best to perform a time-constant compare when verifying a HMAC value if you have to perform the truncation instead.
Using a standardized, truncated version of SHA-2 would be an option if truncation of the hash is not available (e.g. SHA-224 is already a truncated version of SHA-256). It has the disadvantage that the inner security of the hash is lowered together with the output size.
- If I have a function that generates HMAC-SHA-xxx output, then I can create a function that generates HMAC-SHA-xxx-yyy output simply by returning the first yyy bytes of HMAC-SHA-xxx output.
Yes, you'd use the leftmost bits / bytes. yyy would be in bits, so you'd have to devide by 8 (and I would only allow multiples of 8 for yyy).
Beware that the authors of the RFC talk about "recommend" and "propose" in section 5, so the implementation of HMAC-<hash>-yyy seems strictly optional.