Pra quem está acostumado com array, tá simples.
...
PrintBegin()
aEtiqueta := {}
DO WHILE .NOT. Eof()
IF Len( aEtiqueta ) == 3
Imprime( aEtiqueta )
aEtiqueta := {}
ENDIF
AAdd( aEtiqueta, { "ILMO SR(A)", etika->Nome, etika->Endereco, ;
etika->Bairro + " - " + Trim( etika->Cidade ) + " - " + etika->Uf, etika->Cep, "" } )
SKIP
ENDDO
IF Len( aEtiqueta ) > 0
Imprime( aEtiqueta )
ENDIF
PrintEnd()
...
STATIC FUNCTION Imprime( aEtiqueta )
LOCAL nNumLin, nNumCol, nCol
FOR nNumLin = 1 TO Len( aEtiqueta[ 1 ] ) // baseado na primeira etiqueta
FOR nNumCol = 1 TO Len( aEtiqueta )
DO CASE
CASE nNumCol == 1; nCol := 3
CASE nNumCol == 2; nCol := 46
CASE nNumCol == 3; nCol := 89
ENDCASE
@ pRow(), nCol SAY aEtiqueta[ nNumCol ] [ nNumLin ]
NEXT
@ pRow() + 1, 0 SAY ""
NEXT
RETURN NIL
A única dependência da rotina é aEtiqueta, contendo as linhas/colunas.
O ponto interessante é a rotina funcionar "sozinha", pra ajustar a rotina não depende de nenhum nome externo à ela.
PrintBegin() e PrintEnd() é o tradicional set device to print/set device to screen, podendo ter algo mais.
Agora pensei em deixar pronto pra uso geral, talvez até classe.
Começar apenas transformando em classe.