1228072Sbapt/* tables.c - tables serialization code 2228072Sbapt * 3228072Sbapt * Copyright (c) 1990 The Regents of the University of California. 4228072Sbapt * All rights reserved. 5228072Sbapt * 6228072Sbapt * This code is derived from software contributed to Berkeley by 7228072Sbapt * Vern Paxson. 8228072Sbapt * 9228072Sbapt * The United States Government has rights in this work pursuant 10228072Sbapt * to contract no. DE-AC03-76SF00098 between the United States 11228072Sbapt * Department of Energy and the University of California. 12228072Sbapt * 13228072Sbapt * This file is part of flex. 14228072Sbapt * 15228072Sbapt * Redistribution and use in source and binary forms, with or without 16228072Sbapt * modification, are permitted provided that the following conditions 17228072Sbapt * are met: 18228072Sbapt * 19228072Sbapt * 1. Redistributions of source code must retain the above copyright 20228072Sbapt * notice, this list of conditions and the following disclaimer. 21228072Sbapt * 2. Redistributions in binary form must reproduce the above copyright 22228072Sbapt * notice, this list of conditions and the following disclaimer in the 23228072Sbapt * documentation and/or other materials provided with the distribution. 24228072Sbapt * 25228072Sbapt * Neither the name of the University nor the names of its contributors 26228072Sbapt * may be used to endorse or promote products derived from this software 27228072Sbapt * without specific prior written permission. 28228072Sbapt * 29228072Sbapt * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 30228072Sbapt * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 31228072Sbapt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 32228072Sbapt * PURPOSE. 33228072Sbapt */ 34228072Sbapt 35228072Sbapt 36228072Sbapt#include "flexdef.h" 37228072Sbapt#include "tables.h" 38228072Sbapt 39228072Sbapt/** Convert size_t to t_flag. 40228072Sbapt * @param n in {1,2,4} 41228072Sbapt * @return YYTD_DATA*. 42228072Sbapt */ 43228072Sbapt#define BYTES2TFLAG(n)\ 44228072Sbapt (((n) == sizeof(flex_int8_t))\ 45228072Sbapt ? YYTD_DATA8\ 46228072Sbapt :(((n)== sizeof(flex_int16_t))\ 47228072Sbapt ? YYTD_DATA16\ 48228072Sbapt : YYTD_DATA32)) 49228072Sbapt 50228072Sbapt/** Clear YYTD_DATA* bit flags 51228072Sbapt * @return the flag with the YYTD_DATA* bits cleared 52228072Sbapt */ 53228072Sbapt#define TFLAGS_CLRDATA(flg) ((flg) & ~(YYTD_DATA8 | YYTD_DATA16 | YYTD_DATA32)) 54228072Sbapt 55228072Sbaptint yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v); 56228072Sbaptint yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v); 57228072Sbaptint yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v); 58228072Sbaptint yytbl_writen (struct yytbl_writer *wr, void *v, flex_int32_t len); 59228072Sbaptstatic flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i); 60250125Sjkim/* XXX Not used 61228072Sbaptstatic flex_int32_t yytbl_data_getijk (const struct yytbl_data *tbl, int i, 62228072Sbapt int j, int k); 63250125Sjkim */ 64228072Sbapt 65228072Sbapt 66228072Sbapt/** Initialize the table writer. 67228072Sbapt * @param wr an uninitialized writer 68228072Sbapt * @param the output file 69228072Sbapt * @return 0 on success 70228072Sbapt */ 71228072Sbaptint yytbl_writer_init (struct yytbl_writer *wr, FILE * out) 72228072Sbapt{ 73228072Sbapt wr->out = out; 74228072Sbapt wr->total_written = 0; 75228072Sbapt return 0; 76228072Sbapt} 77228072Sbapt 78228072Sbapt/** Initialize a table header. 79228072Sbapt * @param th The uninitialized structure 80228072Sbapt * @param version_str the version string 81228072Sbapt * @param name the name of this table set 82228072Sbapt */ 83228072Sbaptint yytbl_hdr_init (struct yytbl_hdr *th, const char *version_str, 84228072Sbapt const char *name) 85228072Sbapt{ 86228072Sbapt memset (th, 0, sizeof (struct yytbl_hdr)); 87228072Sbapt 88228072Sbapt th->th_magic = YYTBL_MAGIC; 89228072Sbapt th->th_hsize = 14 + strlen (version_str) + 1 + strlen (name) + 1; 90228072Sbapt th->th_hsize += yypad64 (th->th_hsize); 91228072Sbapt th->th_ssize = 0; // Not known at this point. 92228072Sbapt th->th_flags = 0; 93228072Sbapt th->th_version = copy_string (version_str); 94228072Sbapt th->th_name = copy_string (name); 95228072Sbapt return 0; 96228072Sbapt} 97228072Sbapt 98228072Sbapt/** Allocate and initialize a table data structure. 99228072Sbapt * @param tbl a pointer to an uninitialized table 100228072Sbapt * @param id the table identifier 101228072Sbapt * @return 0 on success 102228072Sbapt */ 103228072Sbaptint yytbl_data_init (struct yytbl_data *td, enum yytbl_id id) 104228072Sbapt{ 105228072Sbapt 106228072Sbapt memset (td, 0, sizeof (struct yytbl_data)); 107228072Sbapt td->td_id = id; 108228072Sbapt td->td_flags = YYTD_DATA32; 109228072Sbapt return 0; 110228072Sbapt} 111228072Sbapt 112228072Sbapt/** Clean up table and data array. 113228072Sbapt * @param td will be destroyed 114228072Sbapt * @return 0 on success 115228072Sbapt */ 116228072Sbaptint yytbl_data_destroy (struct yytbl_data *td) 117228072Sbapt{ 118228072Sbapt if (td->td_data) 119228072Sbapt free (td->td_data); 120228072Sbapt td->td_data = 0; 121228072Sbapt free (td); 122228072Sbapt return 0; 123228072Sbapt} 124228072Sbapt 125228072Sbapt/** Write enough padding to bring the file pointer to a 64-bit boundary. */ 126228072Sbaptstatic int yytbl_write_pad64 (struct yytbl_writer *wr) 127228072Sbapt{ 128228072Sbapt int pad, bwritten = 0; 129228072Sbapt 130228072Sbapt pad = yypad64 (wr->total_written); 131228072Sbapt while (pad-- > 0) 132228072Sbapt if (yytbl_write8 (wr, 0) < 0) 133228072Sbapt return -1; 134228072Sbapt else 135228072Sbapt bwritten++; 136228072Sbapt return bwritten; 137228072Sbapt} 138228072Sbapt 139228072Sbapt/** write the header. 140228072Sbapt * @param out the output stream 141228072Sbapt * @param th table header to be written 142228072Sbapt * @return -1 on error, or bytes written on success. 143228072Sbapt */ 144228072Sbaptint yytbl_hdr_fwrite (struct yytbl_writer *wr, const struct yytbl_hdr *th) 145228072Sbapt{ 146228072Sbapt int sz, rv; 147228072Sbapt int bwritten = 0; 148228072Sbapt 149228072Sbapt if (yytbl_write32 (wr, th->th_magic) < 0 150228072Sbapt || yytbl_write32 (wr, th->th_hsize) < 0) 151228072Sbapt flex_die (_("th_magic|th_hsize write32 failed")); 152228072Sbapt bwritten += 8; 153228072Sbapt 154228072Sbapt if (fgetpos (wr->out, &(wr->th_ssize_pos)) != 0) 155228072Sbapt flex_die (_("fgetpos failed")); 156228072Sbapt 157228072Sbapt if (yytbl_write32 (wr, th->th_ssize) < 0 158228072Sbapt || yytbl_write16 (wr, th->th_flags) < 0) 159228072Sbapt flex_die (_("th_ssize|th_flags write failed")); 160228072Sbapt bwritten += 6; 161228072Sbapt 162228072Sbapt sz = strlen (th->th_version) + 1; 163228072Sbapt if ((rv = yytbl_writen (wr, th->th_version, sz)) != sz) 164228072Sbapt flex_die (_("th_version writen failed")); 165228072Sbapt bwritten += rv; 166228072Sbapt 167228072Sbapt sz = strlen (th->th_name) + 1; 168228072Sbapt if ((rv = yytbl_writen (wr, th->th_name, sz)) != sz) 169228072Sbapt flex_die (_("th_name writen failed")); 170228072Sbapt bwritten += rv; 171228072Sbapt 172228072Sbapt /* add padding */ 173228072Sbapt if ((rv = yytbl_write_pad64 (wr)) < 0) 174228072Sbapt flex_die (_("pad64 failed")); 175228072Sbapt bwritten += rv; 176228072Sbapt 177228072Sbapt /* Sanity check */ 178228072Sbapt if (bwritten != (int) th->th_hsize) 179228072Sbapt flex_die (_("pad64 failed")); 180228072Sbapt 181228072Sbapt return bwritten; 182228072Sbapt} 183228072Sbapt 184228072Sbapt 185228072Sbapt/** Write this table. 186228072Sbapt * @param out the file writer 187228072Sbapt * @param td table data to be written 188228072Sbapt * @return -1 on error, or bytes written on success. 189228072Sbapt */ 190228072Sbaptint yytbl_data_fwrite (struct yytbl_writer *wr, struct yytbl_data *td) 191228072Sbapt{ 192228072Sbapt int rv; 193228072Sbapt flex_int32_t bwritten = 0; 194228072Sbapt flex_int32_t i, total_len; 195228072Sbapt fpos_t pos; 196228072Sbapt 197228072Sbapt if ((rv = yytbl_write16 (wr, td->td_id)) < 0) 198228072Sbapt return -1; 199228072Sbapt bwritten += rv; 200228072Sbapt 201228072Sbapt if ((rv = yytbl_write16 (wr, td->td_flags)) < 0) 202228072Sbapt return -1; 203228072Sbapt bwritten += rv; 204228072Sbapt 205228072Sbapt if ((rv = yytbl_write32 (wr, td->td_hilen)) < 0) 206228072Sbapt return -1; 207228072Sbapt bwritten += rv; 208228072Sbapt 209228072Sbapt if ((rv = yytbl_write32 (wr, td->td_lolen)) < 0) 210228072Sbapt return -1; 211228072Sbapt bwritten += rv; 212228072Sbapt 213228072Sbapt total_len = yytbl_calc_total_len (td); 214228072Sbapt for (i = 0; i < total_len; i++) { 215228072Sbapt switch (YYTDFLAGS2BYTES (td->td_flags)) { 216228072Sbapt case sizeof (flex_int8_t): 217228072Sbapt rv = yytbl_write8 (wr, yytbl_data_geti (td, i)); 218228072Sbapt break; 219228072Sbapt case sizeof (flex_int16_t): 220228072Sbapt rv = yytbl_write16 (wr, yytbl_data_geti (td, i)); 221228072Sbapt break; 222228072Sbapt case sizeof (flex_int32_t): 223228072Sbapt rv = yytbl_write32 (wr, yytbl_data_geti (td, i)); 224228072Sbapt break; 225228072Sbapt default: 226228072Sbapt flex_die (_("invalid td_flags detected")); 227228072Sbapt } 228228072Sbapt if (rv < 0) { 229228072Sbapt flex_die (_("error while writing tables")); 230228072Sbapt return -1; 231228072Sbapt } 232228072Sbapt bwritten += rv; 233228072Sbapt } 234228072Sbapt 235228072Sbapt /* Sanity check */ 236228072Sbapt if (bwritten != (int) (12 + total_len * YYTDFLAGS2BYTES (td->td_flags))) { 237228072Sbapt flex_die (_("insanity detected")); 238228072Sbapt return -1; 239228072Sbapt } 240228072Sbapt 241228072Sbapt /* add padding */ 242228072Sbapt if ((rv = yytbl_write_pad64 (wr)) < 0) { 243228072Sbapt flex_die (_("pad64 failed")); 244228072Sbapt return -1; 245228072Sbapt } 246228072Sbapt bwritten += rv; 247228072Sbapt 248228072Sbapt /* Now go back and update the th_hsize member */ 249228072Sbapt if (fgetpos (wr->out, &pos) != 0 250228072Sbapt || fsetpos (wr->out, &(wr->th_ssize_pos)) != 0 251228072Sbapt || yytbl_write32 (wr, wr->total_written) < 0 252228072Sbapt || fsetpos (wr->out, &pos)) { 253228072Sbapt flex_die (_("get|set|fwrite32 failed")); 254228072Sbapt return -1; 255228072Sbapt } 256228072Sbapt else 257228072Sbapt /* Don't count the int we just wrote. */ 258228072Sbapt wr->total_written -= sizeof (flex_int32_t); 259228072Sbapt return bwritten; 260228072Sbapt} 261228072Sbapt 262228072Sbapt/** Write n bytes. 263228072Sbapt * @param wr the table writer 264228072Sbapt * @param v data to be written 265228072Sbapt * @param len number of bytes 266228072Sbapt * @return -1 on error. number of bytes written on success. 267228072Sbapt */ 268228072Sbaptint yytbl_writen (struct yytbl_writer *wr, void *v, flex_int32_t len) 269228072Sbapt{ 270228072Sbapt int rv; 271228072Sbapt 272228072Sbapt rv = fwrite (v, 1, len, wr->out); 273228072Sbapt if (rv != len) 274228072Sbapt return -1; 275228072Sbapt wr->total_written += len; 276228072Sbapt return len; 277228072Sbapt} 278228072Sbapt 279228072Sbapt/** Write four bytes in network byte order 280228072Sbapt * @param wr the table writer 281228072Sbapt * @param v a dword in host byte order 282228072Sbapt * @return -1 on error. number of bytes written on success. 283228072Sbapt */ 284228072Sbaptint yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v) 285228072Sbapt{ 286228072Sbapt flex_uint32_t vnet; 287228072Sbapt size_t bytes, rv; 288228072Sbapt 289228072Sbapt vnet = htonl (v); 290228072Sbapt bytes = sizeof (flex_uint32_t); 291228072Sbapt rv = fwrite (&vnet, bytes, 1, wr->out); 292228072Sbapt if (rv != 1) 293228072Sbapt return -1; 294228072Sbapt wr->total_written += bytes; 295228072Sbapt return bytes; 296228072Sbapt} 297228072Sbapt 298228072Sbapt/** Write two bytes in network byte order. 299228072Sbapt * @param wr the table writer 300228072Sbapt * @param v a word in host byte order 301228072Sbapt * @return -1 on error. number of bytes written on success. 302228072Sbapt */ 303228072Sbaptint yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v) 304228072Sbapt{ 305228072Sbapt flex_uint16_t vnet; 306228072Sbapt size_t bytes, rv; 307228072Sbapt 308228072Sbapt vnet = htons (v); 309228072Sbapt bytes = sizeof (flex_uint16_t); 310228072Sbapt rv = fwrite (&vnet, bytes, 1, wr->out); 311228072Sbapt if (rv != 1) 312228072Sbapt return -1; 313228072Sbapt wr->total_written += bytes; 314228072Sbapt return bytes; 315228072Sbapt} 316228072Sbapt 317228072Sbapt/** Write a byte. 318228072Sbapt * @param wr the table writer 319228072Sbapt * @param v the value to be written 320228072Sbapt * @return -1 on error. number of bytes written on success. 321228072Sbapt */ 322228072Sbaptint yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v) 323228072Sbapt{ 324228072Sbapt size_t bytes, rv; 325228072Sbapt 326228072Sbapt bytes = sizeof (flex_uint8_t); 327228072Sbapt rv = fwrite (&v, bytes, 1, wr->out); 328228072Sbapt if (rv != 1) 329228072Sbapt return -1; 330228072Sbapt wr->total_written += bytes; 331228072Sbapt return bytes; 332228072Sbapt} 333228072Sbapt 334228072Sbapt 335250125Sjkim/* XXX Not Used */ 336250125Sjkim#if 0 337228072Sbapt/** Extract data element [i][j] from array data tables. 338228072Sbapt * @param tbl data table 339228072Sbapt * @param i index into higher dimension array. i should be zero for one-dimensional arrays. 340228072Sbapt * @param j index into lower dimension array. 341228072Sbapt * @param k index into struct, must be 0 or 1. Only valid for YYTD_ID_TRANSITION table 342228072Sbapt * @return data[i][j + k] 343228072Sbapt */ 344228072Sbaptstatic flex_int32_t yytbl_data_getijk (const struct yytbl_data *tbl, int i, 345228072Sbapt int j, int k) 346228072Sbapt{ 347228072Sbapt flex_int32_t lo; 348228072Sbapt 349228072Sbapt k %= 2; 350228072Sbapt lo = tbl->td_lolen; 351228072Sbapt 352228072Sbapt switch (YYTDFLAGS2BYTES (tbl->td_flags)) { 353228072Sbapt case sizeof (flex_int8_t): 354228072Sbapt return ((flex_int8_t *) (tbl->td_data))[(i * lo + j) * (k + 1) + 355228072Sbapt k]; 356228072Sbapt case sizeof (flex_int16_t): 357228072Sbapt return ((flex_int16_t *) (tbl->td_data))[(i * lo + j) * (k + 358228072Sbapt 1) + 359228072Sbapt k]; 360228072Sbapt case sizeof (flex_int32_t): 361228072Sbapt return ((flex_int32_t *) (tbl->td_data))[(i * lo + j) * (k + 362228072Sbapt 1) + 363228072Sbapt k]; 364228072Sbapt default: 365228072Sbapt flex_die (_("invalid td_flags detected")); 366228072Sbapt break; 367228072Sbapt } 368228072Sbapt 369228072Sbapt return 0; 370228072Sbapt} 371250125Sjkim#endif /* Not used */ 372228072Sbapt 373228072Sbapt/** Extract data element [i] from array data tables treated as a single flat array of integers. 374228072Sbapt * Be careful for 2-dimensional arrays or for YYTD_ID_TRANSITION, which is an array 375228072Sbapt * of structs. 376228072Sbapt * @param tbl data table 377228072Sbapt * @param i index into array. 378228072Sbapt * @return data[i] 379228072Sbapt */ 380228072Sbaptstatic flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i) 381228072Sbapt{ 382228072Sbapt 383228072Sbapt switch (YYTDFLAGS2BYTES (tbl->td_flags)) { 384228072Sbapt case sizeof (flex_int8_t): 385228072Sbapt return ((flex_int8_t *) (tbl->td_data))[i]; 386228072Sbapt case sizeof (flex_int16_t): 387228072Sbapt return ((flex_int16_t *) (tbl->td_data))[i]; 388228072Sbapt case sizeof (flex_int32_t): 389228072Sbapt return ((flex_int32_t *) (tbl->td_data))[i]; 390228072Sbapt default: 391228072Sbapt flex_die (_("invalid td_flags detected")); 392228072Sbapt break; 393228072Sbapt } 394228072Sbapt return 0; 395228072Sbapt} 396228072Sbapt 397228072Sbapt/** Set data element [i] in array data tables treated as a single flat array of integers. 398228072Sbapt * Be careful for 2-dimensional arrays or for YYTD_ID_TRANSITION, which is an array 399228072Sbapt * of structs. 400228072Sbapt * @param tbl data table 401228072Sbapt * @param i index into array. 402228072Sbapt * @param newval new value for data[i] 403228072Sbapt */ 404228072Sbaptstatic void yytbl_data_seti (const struct yytbl_data *tbl, int i, 405228072Sbapt flex_int32_t newval) 406228072Sbapt{ 407228072Sbapt 408228072Sbapt switch (YYTDFLAGS2BYTES (tbl->td_flags)) { 409228072Sbapt case sizeof (flex_int8_t): 410228072Sbapt ((flex_int8_t *) (tbl->td_data))[i] = (flex_int8_t) newval; 411228072Sbapt break; 412228072Sbapt case sizeof (flex_int16_t): 413228072Sbapt ((flex_int16_t *) (tbl->td_data))[i] = (flex_int16_t) newval; 414228072Sbapt break; 415228072Sbapt case sizeof (flex_int32_t): 416228072Sbapt ((flex_int32_t *) (tbl->td_data))[i] = (flex_int32_t) newval; 417228072Sbapt break; 418228072Sbapt default: 419228072Sbapt flex_die (_("invalid td_flags detected")); 420228072Sbapt break; 421228072Sbapt } 422228072Sbapt} 423228072Sbapt 424228072Sbapt/** Calculate the number of bytes needed to hold the largest 425228072Sbapt * absolute value in this data array. 426228072Sbapt * @param tbl the data table 427228072Sbapt * @return sizeof(n) where n in {flex_int8_t, flex_int16_t, flex_int32_t} 428228072Sbapt */ 429228072Sbaptstatic size_t min_int_size (struct yytbl_data *tbl) 430228072Sbapt{ 431228072Sbapt flex_uint32_t i, total_len; 432228072Sbapt flex_int32_t max = 0; 433228072Sbapt 434228072Sbapt total_len = yytbl_calc_total_len (tbl); 435228072Sbapt 436228072Sbapt for (i = 0; i < total_len; i++) { 437228072Sbapt flex_int32_t n; 438228072Sbapt 439228072Sbapt n = abs (yytbl_data_geti (tbl, i)); 440228072Sbapt 441228072Sbapt if (n > max) 442228072Sbapt max = n; 443228072Sbapt } 444228072Sbapt 445228072Sbapt if (max <= INT8_MAX) 446228072Sbapt return sizeof (flex_int8_t); 447228072Sbapt else if (max <= INT16_MAX) 448228072Sbapt return sizeof (flex_int16_t); 449228072Sbapt else 450228072Sbapt return sizeof (flex_int32_t); 451228072Sbapt} 452228072Sbapt 453228072Sbapt/** Transform data to smallest possible of (int32, int16, int8). 454228072Sbapt * For example, we may have generated an int32 array due to user options 455228072Sbapt * (e.g., %option align), but if the maximum value in that array 456228072Sbapt * is 80 (for example), then we can serialize it with only 1 byte per int. 457228072Sbapt * This is NOT the same as compressed DFA tables. We're just trying 458228072Sbapt * to save storage space here. 459228072Sbapt * 460228072Sbapt * @param tbl the table to be compressed 461228072Sbapt */ 462228072Sbaptvoid yytbl_data_compress (struct yytbl_data *tbl) 463228072Sbapt{ 464228072Sbapt flex_int32_t i, newsz, total_len; 465228072Sbapt struct yytbl_data newtbl; 466228072Sbapt 467228072Sbapt yytbl_data_init (&newtbl, tbl->td_id); 468228072Sbapt newtbl.td_hilen = tbl->td_hilen; 469228072Sbapt newtbl.td_lolen = tbl->td_lolen; 470228072Sbapt newtbl.td_flags = tbl->td_flags; 471228072Sbapt 472228072Sbapt newsz = min_int_size (tbl); 473228072Sbapt 474228072Sbapt 475228072Sbapt if (newsz == (int) YYTDFLAGS2BYTES (tbl->td_flags)) 476228072Sbapt /* No change in this table needed. */ 477228072Sbapt return; 478228072Sbapt 479228072Sbapt if (newsz > (int) YYTDFLAGS2BYTES (tbl->td_flags)) { 480228072Sbapt flex_die (_("detected negative compression")); 481228072Sbapt return; 482228072Sbapt } 483228072Sbapt 484228072Sbapt total_len = yytbl_calc_total_len (tbl); 485228072Sbapt newtbl.td_data = calloc (total_len, newsz); 486228072Sbapt newtbl.td_flags = 487228072Sbapt TFLAGS_CLRDATA (newtbl.td_flags) | BYTES2TFLAG (newsz); 488228072Sbapt 489228072Sbapt for (i = 0; i < total_len; i++) { 490228072Sbapt flex_int32_t g; 491228072Sbapt 492228072Sbapt g = yytbl_data_geti (tbl, i); 493228072Sbapt yytbl_data_seti (&newtbl, i, g); 494228072Sbapt } 495228072Sbapt 496228072Sbapt 497228072Sbapt /* Now copy over the old table */ 498228072Sbapt free (tbl->td_data); 499228072Sbapt *tbl = newtbl; 500228072Sbapt} 501228072Sbapt 502228072Sbapt/* vim:set noexpandtab cindent tabstop=8 softtabstop=0 shiftwidth=8 textwidth=0: */ 503