syn-intel.c revision f2477e01787aa58f445919b809d89e252beef54f
1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/* udis86 - libudis86/syn-intel.c 2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * 3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Copyright (c) 2002-2013 Vivek Thampi 4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * All rights reserved. 5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * 6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without modification, 7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * are permitted provided that the following conditions are met: 8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * 9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * * Redistributions of source code must retain the above copyright notice, 10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * this list of conditions and the following disclaimer. 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * * Redistributions in binary form must reproduce the above copyright notice, 12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * this list of conditions and the following disclaimer in the documentation 13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * and/or other materials provided with the distribution. 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "types.h" 27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extern.h" 28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "decode.h" 29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "itab.h" 30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "syn.h" 31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "udint.h" 32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/* ----------------------------------------------------------------------------- 34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * opr_cast() - Prints an operand cast. 35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * ----------------------------------------------------------------------------- 36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)static void 38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)opr_cast(struct ud* u, struct ud_operand* op) 39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles){ 40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (u->br_far) { 41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "far "); 42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) switch(op->size) { 44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case 8: ud_asmprintf(u, "byte " ); break; 45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case 16: ud_asmprintf(u, "word " ); break; 46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case 32: ud_asmprintf(u, "dword "); break; 47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case 64: ud_asmprintf(u, "qword "); break; 48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case 80: ud_asmprintf(u, "tword "); break; 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) default: break; 50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/* ----------------------------------------------------------------------------- 54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * gen_operand() - Generates assembly output for each operand. 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * ----------------------------------------------------------------------------- 56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)static void gen_operand(struct ud* u, struct ud_operand* op, int syn_cast) 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles){ 59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) switch(op->type) { 60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case UD_OP_REG: 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "%s", ud_reg_tab[op->base - UD_R_AL]); 62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case UD_OP_MEM: 65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (syn_cast) { 66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) opr_cast(u, op); 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "["); 69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (u->pfx_seg) { 70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]); 71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (op->base) { 73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "%s", ud_reg_tab[op->base - UD_R_AL]); 74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (op->index) { 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "%s%s", op->base != UD_NONE? "+" : "", 77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_reg_tab[op->index - UD_R_AL]); 78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (op->scale) { 79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "*%d", op->scale); 80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (op->offset != 0) { 83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_syn_print_mem_disp(u, op, (op->base != UD_NONE || 84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) op->index != UD_NONE) ? 1 : 0); 85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "]"); 87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case UD_OP_IMM: 90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_syn_print_imm(u, op); 91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case UD_OP_JIMM: 95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_syn_print_addr(u, ud_syn_rel_target(u, op)); 96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case UD_OP_PTR: 99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) switch (op->size) { 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case 32: 101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "word 0x%x:0x%x", op->lval.ptr.seg, 102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) op->lval.ptr.off & 0xFFFF); 103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case 48: 105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "dword 0x%x:0x%x", op->lval.ptr.seg, 106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) op->lval.ptr.off); 107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case UD_OP_CONST: 112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (syn_cast) opr_cast(u, op); 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "%d", op->lval.udword); 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) default: return; 117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/* ============================================================================= 121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * translates to intel syntax 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * ============================================================================= 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)extern void 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ud_translate_intel(struct ud* u) 126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles){ 127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /* check if P_OSO prefix is used */ 128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!P_OSO(u->itab_entry->prefix) && u->pfx_opr) { 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) switch (u->dis_mode) { 130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case 16: ud_asmprintf(u, "o32 "); break; 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case 32: 132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case 64: ud_asmprintf(u, "o16 "); break; 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /* check if P_ASO prefix was used */ 137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!P_ASO(u->itab_entry->prefix) && u->pfx_adr) { 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) switch (u->dis_mode) { 139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case 16: ud_asmprintf(u, "a32 "); break; 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case 32: ud_asmprintf(u, "a16 "); break; 141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case 64: ud_asmprintf(u, "a32 "); break; 142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (u->pfx_seg && 146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) u->operand[0].type != UD_OP_MEM && 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) u->operand[1].type != UD_OP_MEM ) { 148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "%s ", ud_reg_tab[u->pfx_seg - UD_R_AL]); 149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (u->pfx_lock) { 152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "lock "); 153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (u->pfx_rep) { 155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "rep "); 156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else if (u->pfx_repe) { 157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "repe "); 158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else if (u->pfx_repne) { 159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "repne "); 160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /* print the instruction mnemonic */ 163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic)); 164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (u->operand[0].type != UD_NONE) { 166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int cast = 0; 167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, " "); 168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (u->operand[0].type == UD_OP_MEM) { 169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (u->operand[1].type == UD_OP_IMM || 170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) u->operand[1].type == UD_OP_CONST || 171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) u->operand[1].type == UD_NONE || 172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) (u->operand[0].size != u->operand[1].size && 173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) u->operand[1].type != UD_OP_REG)) { 174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) cast = 1; 175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else if (u->operand[1].type == UD_OP_REG && 176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) u->operand[1].base == UD_R_CL) { 177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) switch (u->mnemonic) { 178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case UD_Ircl: 179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case UD_Irol: 180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case UD_Iror: 181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case UD_Ircr: 182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case UD_Ishl: 183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case UD_Ishr: 184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case UD_Isar: 185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) cast = 1; 186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) default: break; 188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gen_operand(u, &u->operand[0], cast); 192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (u->operand[1].type != UD_NONE) { 195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int cast = 0; 196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, ", "); 197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (u->operand[1].type == UD_OP_MEM && 198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) u->operand[0].size != u->operand[1].size && 199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) !ud_opr_is_sreg(&u->operand[0])) { 200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) cast = 1; 201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gen_operand(u, &u->operand[1], cast); 203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (u->operand[2].type != UD_NONE) { 206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ud_asmprintf(u, ", "); 207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gen_operand(u, &u->operand[2], 0); 208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/* 212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)vim: set ts=2 sw=2 expandtab 213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)*/ 214