home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 5 / 05.iso / a / a009 / 6.ddi / DBU.LIF / DBUSTRU.PRG < prev    next >
Encoding:
Text File  |  1991-04-14  |  25.8 KB  |  1,332 lines

  1. ************
  2. *
  3. *    Program....:  DBU
  4. *    Filename...:  DBUSTRU.PRG
  5. *    Author.....:  Dennis L. Dias
  6. *    Date.......:  06/18/86, 06/18/90
  7. *    Purpose....:  Create/Modify Structure Module
  8. *
  9. *    Copyright (c) 1986-1990 Nantucket Corp., All Rights Reserved.
  10. *
  11. ************
  12.  
  13.  
  14. ******
  15. *    modi_stru
  16. *
  17. *    create or modify the structure of a database file
  18. ******
  19. PROCEDURE modi_stru
  20. local saveColor
  21. PRIVATE filename,fill_row,cur_row,rec1,m_item,i,n,f_name,f_type,f_len,f_dec,;
  22.         prev_rec,field_id,stru_ok,is_insert,is_append,altered,type_n,;
  23.         empty_row,not_empty,old_help,chg_name,len_temp,stru_name,;
  24.         wstru_buff
  25.  
  26. * save help code
  27. old_help = help_code
  28. saveColor := SetColor(M->color7)
  29.  
  30. * allocate buffer and save window
  31. wstru_buff = SAVESCREEN(8, 20, 23, 59)
  32.  
  33. * local arrays..constant values
  34. DECLARE ffield[4]
  35. DECLARE field_col[4]
  36. DECLARE data_type[5]
  37. DECLARE l_usr[5]
  38.  
  39. * field list for structure file
  40. ffield[1] = "field_name"
  41. ffield[2] = "field_type"
  42. ffield[3] = "field_len"
  43. ffield[4] = "field_dec"
  44.  
  45. * display columns for ffield[]
  46. field_col[1] = 22
  47. field_col[2] = 35
  48. field_col[3] = 48
  49. field_col[4] = 55
  50.  
  51. * data types as character strings
  52. data_type[1] = "Character"
  53. data_type[2] = "Numeric  "
  54. data_type[3] = "Date     "
  55. data_type[4] = "Logical  "
  56. data_type[5] = "Memo     "
  57.  
  58. * last user definable ffield for each data type
  59. l_usr[1] = 3            && character - variable len
  60. l_usr[2] = 4            && numeric - variable len and dec
  61. l_usr[3] = 2            && date - fixed len - 8
  62. l_usr[4] = 2            && logical - fixed len - 1
  63. l_usr[5] = 2            && memo - fixed len - 10
  64.  
  65. * initialize local variables
  66. type_n = 1                && index into data types
  67. altered = .F.            && any changes?
  68. chg_name = .T.            && possible to change field names?
  69. prev_rec = 0            && detect record movement
  70. n = 1                    && current cursor column (1 - 4)
  71. i = 0                    && invalid field aspect
  72. cur_row = 13            && current cursor row
  73. is_insert = .F.            && .T. if insert new field
  74. keystroke = 999            && for initial screen fill
  75. filename = ""            && variable for "filebox" function
  76.  
  77. * sigle row templates
  78. empty_row = "           │           │       │    "
  79. not_empty = "           │ Character │    10 │    "
  80.  
  81. IF .NOT. EMPTY(M->cur_dbf)
  82.     * modify structure
  83.     stat_msg("Reading file structure")
  84.     stru_name = M->cur_dbf
  85.     SELECT (M->cur_area)
  86.  
  87.     * create system structure extended file
  88.     COPY TO ddbbuuuu.ext STRUCTURE EXTENDED
  89.  
  90.     * open structure extended file in system reserved select area
  91.     SELECT 10
  92.     USE ddbbuuuu.ext
  93.  
  94.     * structure is valid and no new fields added
  95.     stru_ok = .T.
  96.     is_append = .F.
  97.  
  98.     * update screen header
  99.     stat_msg("")
  100.  
  101. ELSE
  102.     * create structure
  103.     SELECT 10
  104.     CREATE ddbbuuuu.ext
  105.  
  106.     * add first new field as yet undefined
  107.     APPEND BLANK
  108.     REPLACE field_type WITH "C",field_len WITH 10,field_dec WITH 0
  109.  
  110.     * structure is not valid
  111.     stru_ok = .F.
  112.     is_append = .T.
  113.     stru_name = ""
  114.  
  115. ENDIF
  116.  
  117. * clear and frame window
  118. scroll(8, 20, 23, 59, 0)
  119. @ 8, 20, 23, 59 BOX M->frame
  120.  
  121. * establish window heading
  122. @ 9,field_col[1];
  123. SAY "Structure of " + pad(IF(EMPTY(stru_name), "<new file>",;
  124.                             SUBSTR(stru_name, RAT("\", stru_name) + 1)), 13)
  125.  
  126. @ 11,22 SAY   "Field Name   Type        Width   Dec"
  127. @ 12,20 SAY "╞════════════╤═══════════╤═══════╤═════╡"
  128. @ 23,33 SAY              "╧═══════════╧═══════╧"
  129.  
  130. DO WHILE .NOT. q_check()
  131.     * the big switch
  132.  
  133.     DO CASE
  134.  
  135.         CASE keystroke = 999
  136.             * draw window
  137.             scroll(13, 21, 22, 58, 0)            && clear window
  138.             rec1 = RECNO()                        && first record in window
  139.             fill_row = 13                        && first row to fill
  140.  
  141.             DO WHILE .NOT. EOF() .AND. fill_row <= 22
  142.                 * fill the window
  143.                 stru_row(fill_row)
  144.  
  145.                 * next field/record number
  146.                 SKIP
  147.                 fill_row = fill_row + 1
  148.  
  149.             ENDDO
  150.  
  151.             DO WHILE fill_row <= 22
  152.                 * end of file..complete vertical bar lines
  153.                 @ fill_row,field_col[1] SAY empty_row
  154.                 fill_row = fill_row + 1
  155.  
  156.             ENDDO
  157.  
  158.             * adjust record pointer to current row
  159.             GOTO rec1
  160.             fill_row = 13
  161.  
  162.             DO WHILE fill_row < cur_row
  163.                 * move to same row if possible
  164.                 SKIP
  165.  
  166.                 IF EOF()
  167.                     * can't go all the way
  168.                     cur_row = fill_row
  169.                     GO BOTTOM
  170.                     EXIT
  171.  
  172.                 ENDIF
  173.  
  174.                 fill_row = fill_row + 1
  175.  
  176.             ENDDO
  177.  
  178.             keystroke = 0            && get new keystroke
  179.  
  180.         CASE keystroke = 13 .OR. isdata(keystroke)
  181.             * enter/select something
  182.  
  183.             IF n = 2
  184.                 * field_type gets special treatment
  185.                 type_n = AT(field_type, "CNDLM")
  186.  
  187.             ELSE
  188.                 * turn on cursor for GET
  189.                 SET CURSOR ON
  190.  
  191.                 IF keystroke <> 13
  192.                     * forward data character to GET system
  193.                     KEYBOARD CHR(keystroke)
  194.  
  195.                 ENDIF
  196.             ENDIF
  197.  
  198.             * get descriptor fieldname to normal variable for macro expansion
  199.             field_id = ffield[n]
  200.  
  201.             * save item to test for change
  202.             m_item = &field_id
  203.  
  204.             * set up and down arrows and menu keys to exit read
  205.             SET KEY 5 TO clear_gets
  206.             SET KEY 24 TO clear_gets
  207.             xkey_clear()
  208.  
  209.             DO CASE
  210.  
  211.                 CASE n = 1
  212.                     * get is for field_name..force all caps
  213.                     SetColor(M->color1)
  214.                     @ cur_row,field_col[1] GET field_name PICTURE "@!K"
  215.                     READ
  216.                     SetColor(M->color7)
  217.                     keystroke = LASTKEY()
  218.  
  219.                 CASE n = 2
  220.                     * special treatment for field_type
  221.  
  222.                     DO CASE
  223.  
  224.                         CASE UPPER(CHR(keystroke)) $ "CNDLM"
  225.                             * set field type to one of C, N, D, L, or M
  226.                             type_n = AT(UPPER(CHR(keystroke)), "CNDLM")
  227.                             keystroke = 13
  228.  
  229.                         CASE keystroke = 32
  230.                             * space bar..revolving field types
  231.                             type_n = IF(type_n = 5, 1, type_n + 1)
  232.  
  233.                         CASE keystroke <> 13
  234.                             * return key behaves like right arrow
  235.                             keystroke = 0
  236.  
  237.                     ENDCASE
  238.  
  239.                     IF m_item <> SUBSTR("CNDLM", type_n, 1)
  240.                         * set new field_type from type_n
  241.                         REPLACE field_type WITH SUBSTR("CNDLM", type_n, 1)
  242.  
  243.                         DO CASE
  244.                             * set field_len and field_dec according to type
  245.  
  246.                             CASE field_type = "C"
  247.                                 * character..any len will do, but not any dec
  248.                                 REPLACE field_dec WITH 0
  249.  
  250.                             CASE field_type = "N"
  251.                                 * numeric
  252.  
  253.                                 IF m_item = "C" .AND. (field_dec <> 0 .OR.;
  254.                                    field_len > 19)
  255.                                     * too long or Clipper extended len
  256.                                     REPLACE field_len WITH 10,field_dec WITH 0
  257.  
  258.                                 ENDIF
  259.  
  260.                             CASE field_type = "D"
  261.                                 * date..always 8
  262.                                 REPLACE field_len WITH 8,field_dec WITH 0
  263.  
  264.                             CASE field_type = "L"
  265.                                 * logical..always 1
  266.                                 REPLACE field_len WITH 1,field_dec WITH 0
  267.  
  268.                             CASE field_type = "M"
  269.                                 * memo..always 10
  270.                                 REPLACE field_len WITH 10,field_dec WITH 0
  271.  
  272.                         ENDCASE
  273.  
  274.                         * display new field_len
  275.                         @ cur_row,field_col[3] SAY STR(field_len,4)
  276.  
  277.                         IF field_type = "N"
  278.                             * display new field_dec
  279.                             @ cur_row,field_col[4] SAY field_dec
  280.  
  281.                         ELSE
  282.                             * ensure a blank field_dec column
  283.                             @ cur_row,field_col[4] SAY "   "
  284.  
  285.                         ENDIF
  286.                     ENDIF new type
  287.  
  288.                 CASE n = 3
  289.                     * get is for field_len
  290.  
  291.                     IF field_type = "C"
  292.                         * get Clipper extended field length into memvar
  293.                         len_temp = (256 * field_dec) + field_len
  294.  
  295.                     ELSE
  296.                         * normal field_len
  297.                         len_temp = field_len
  298.  
  299.                     ENDIF
  300.  
  301.                     * get the new length
  302.                     SetColor(M->color1)
  303.                     @ cur_row,field_col[n] GET len_temp PICTURE "9999"
  304.                     READ
  305.                     SetColor(M->color7)
  306.                     keystroke = LASTKEY()
  307.  
  308.                     IF menu_key() = 0
  309.                         * no menu request
  310.  
  311.                         IF field_type = "C"
  312.                             * put Clipper extended field length into len/dec
  313.                             REPLACE field_len WITH (len_temp % 256)
  314.                             REPLACE field_dec WITH INT(len_temp / 256)
  315.  
  316.                         ELSE
  317.  
  318.                             IF len_temp < 256
  319.                                 * may not be a valid length
  320.                                 REPLACE field_len WITH len_temp
  321.  
  322.                             ELSE
  323.                                 * entry not accepted
  324.                                 keystroke = 0
  325.  
  326.                             ENDIF
  327.                         ENDIF
  328.                     ENDIF
  329.  
  330.                 CASE n = 4
  331.                     * get is for field_dec
  332.                     SetColor(M->color1)
  333.                     @ cur_row,field_col[n] GET field_dec
  334.                     READ
  335.                     SetColor(M->color7)
  336.                     keystroke = LASTKEY()
  337.  
  338.             ENDCASE
  339.  
  340.             * release keys and wipe that cursor off the screen
  341.             SET KEY 5 TO
  342.             SET KEY 24 TO
  343.             xkey_norm()
  344.             SET CURSOR OFF
  345.  
  346.             IF menu_key() <> 0
  347.                 * restore the item and forward the menu key
  348.                 REPLACE &field_id WITH m_item
  349.                 KEYBOARD CHR(keystroke)
  350.  
  351.             ENDIF
  352.  
  353.             IF m_item <> &field_id
  354.                 * something has been changed
  355.                 stru_ok = .F.        && fieldspec may not be valid
  356.                 altered = .T.        && structure is altered
  357.  
  358.                 IF n > 1
  359.                     * can no longer change field names
  360.                     chg_name = .F.
  361.  
  362.                 ENDIF
  363.             ENDIF
  364.  
  365.             DO CASE
  366.  
  367.                 CASE keystroke = 18 .OR. keystroke = 5
  368.                     * up arrow or PgUp...move up
  369.                     keystroke = 5
  370.  
  371.                 CASE keystroke = 3 .OR. keystroke = 24
  372.                     * down arrow or PgDn...move down
  373.                     keystroke = 24
  374.  
  375.                 CASE keystroke = 13 .OR.;
  376.                      (isdata(keystroke) .AND. keystroke <> 32)
  377.                     * next field..space bar is used for revolving data types
  378.                     keystroke = 4
  379.  
  380.                 OTHERWISE
  381.                     * same field
  382.                     keystroke = 0
  383.  
  384.             ENDCASE
  385.  
  386.             * de-hilite the current item 
  387.             stru_item()
  388.  
  389.         CASE keystroke = 5 .AND. RECNO() > 1
  390.             * up arrow
  391.  
  392.             IF is_append
  393.                 * test newly appended field
  394.  
  395.                 IF .NOT. stru_ck(.F.)
  396.                     * delete newly appended field if exit up
  397.                     no_append()
  398.  
  399.                 ENDIF
  400.             ENDIF
  401.  
  402.             IF stru_ck(.T.)
  403.                 * move up one field
  404.                 SKIP -1
  405.  
  406.                 IF cur_row = 13
  407.                     * scroll required
  408.                     scroll(13, 21, 22, 58, -1)
  409.  
  410.                     * fill the blank row
  411.                     stru_row(13)
  412.  
  413.                 ELSE
  414.                     cur_row = cur_row - 1
  415.  
  416.                 ENDIF
  417.  
  418.                 is_append = .F.
  419.                 is_insert = .F.
  420.  
  421.             ELSE
  422.                 * fieldspec no good
  423.                 n = i
  424.  
  425.             ENDIF
  426.  
  427.             keystroke = 0
  428.  
  429.         CASE keystroke = 24
  430.             * down arrow
  431.  
  432.             IF stru_ck(RECNO() < LASTREC())
  433.                 * ok to move down one field
  434.                 SKIP
  435.  
  436.                 IF EOF()
  437.                     * down arrow will append
  438.                     APPEND BLANK
  439.                     REPLACE field_type WITH "C",field_len WITH 10,;
  440.                             field_dec WITH 0
  441.                     is_append = .T.
  442.                     stru_ok = .F.
  443.                     n = 1
  444.  
  445.                     IF cur_row < 22
  446.                         * show new field template
  447.                         @ cur_row + 1, field_col[1] SAY not_empty
  448.  
  449.                     ENDIF
  450.  
  451.                 ELSE
  452.                     is_insert = .F.
  453.  
  454.                 ENDIF
  455.  
  456.                 IF cur_row = 22
  457.                     * scroll required
  458.                     scroll(13, 21, 22, 58, 1)
  459.  
  460.                     * fill the blank row
  461.                     stru_row(22)
  462.  
  463.                 ELSE
  464.                     cur_row = cur_row + 1
  465.  
  466.                 ENDIF
  467.  
  468.             ELSE
  469.                 * fieldspec no good
  470.                 n = i
  471.  
  472.             ENDIF
  473.  
  474.             keystroke = 0
  475.  
  476.         CASE keystroke = 4
  477.             * right arrow
  478.  
  479.             IF n < l_usr[AT(field_type, "CNDLM")]
  480.                 n = n + 1
  481.  
  482.             ENDIF
  483.  
  484.             keystroke = 0
  485.  
  486.         CASE keystroke = 19
  487.             * left arrow
  488.  
  489.             IF n > 1
  490.                 n = n - 1
  491.  
  492.             ENDIF
  493.  
  494.             keystroke = 0
  495.  
  496.         CASE keystroke = 18
  497.             * PgUp
  498.             keystroke = 0
  499.  
  500.             IF RECNO() = 1
  501.                 * avoid re-draw if top of file
  502.                 LOOP
  503.  
  504.             ENDIF
  505.  
  506.             IF is_append
  507.                 * test newly appended field
  508.  
  509.                 IF .NOT. stru_ck(.F.)
  510.                     * delete newly appended field if exit up
  511.                     no_append()
  512.  
  513.                 ENDIF
  514.             ENDIF
  515.  
  516.             IF stru_ck(.T.)
  517.                 is_append = .F.
  518.                 is_insert = .F.
  519.  
  520.                 IF RECNO() = cur_row - 12
  521.                     * record 1 is on screen..no re-draw
  522.                     GO TOP
  523.                     cur_row = 13
  524.  
  525.                 ELSE
  526.                     * skip one page up and re-draw
  527.                     SKIP -(9 + cur_row - 13)
  528.                     keystroke = 999
  529.  
  530.                 ENDIF
  531.  
  532.             ELSE
  533.                 * fieldspec no good..no page up
  534.                 n = i
  535.  
  536.             ENDIF
  537.  
  538.         CASE keystroke = 3
  539.             * PgDn
  540.             keystroke = 0
  541.  
  542.             IF is_append
  543.                 * avoid error messages
  544.                 LOOP
  545.  
  546.             ENDIF
  547.  
  548.             IF stru_ck(.T.)
  549.                 is_insert = .F.
  550.  
  551.                 IF LASTREC() - RECNO() <= 22 - cur_row
  552.                     * last field is on screen
  553.                     cur_row = cur_row + LASTREC() - RECNO()
  554.                     GO BOTTOM
  555.  
  556.                 ELSE
  557.                     * skip one page down
  558.                     keystroke = 999            && cause re-draw of window
  559.                     SKIP 9 - (cur_row - 13)
  560.  
  561.                     IF EOF()
  562.                         * skip incomplete
  563.                         GO BOTTOM
  564.  
  565.                     ENDIF
  566.                 ENDIF
  567.  
  568.             ELSE
  569.                 * fieldspec no good
  570.                 n = i
  571.  
  572.             ENDIF
  573.  
  574.         CASE keystroke = 31
  575.             * ^PgUp..go to top of structure file
  576.             keystroke = 0
  577.  
  578.             IF RECNO() = 1
  579.                 * top of file
  580.                 LOOP
  581.  
  582.             ENDIF
  583.  
  584.             IF is_append
  585.                 * test newly appended field
  586.  
  587.                 IF .NOT. stru_ck(.F.)
  588.                     * delete newly appended field if exit up
  589.                     no_append()
  590.  
  591.                 ENDIF
  592.             ENDIF
  593.  
  594.             IF stru_ck(.T.)
  595.                 is_append = .F.
  596.                 is_insert = .F.
  597.  
  598.                 IF RECNO() > cur_row - 12
  599.                     * record 1 is not on screen
  600.                     keystroke = 999
  601.  
  602.                 ENDIF
  603.  
  604.                 GO TOP
  605.                 cur_row = 13
  606.  
  607.             ELSE
  608.                 * fieldspec no good
  609.                 n = i
  610.  
  611.             ENDIF
  612.  
  613.         CASE keystroke = 30
  614.             * ^PgDn
  615.             keystroke = 0
  616.  
  617.             IF is_append
  618.                 * avoid error messages
  619.                 LOOP
  620.  
  621.             ENDIF
  622.  
  623.             IF stru_ck(.T.)
  624.                 is_insert = .F.
  625.  
  626.                 IF LASTREC() - RECNO() <= 22 - cur_row
  627.                     * last field is on screen
  628.                     cur_row = cur_row + LASTREC() - RECNO()
  629.                     GO BOTTOM
  630.  
  631.                 ELSE
  632.                     * re-draw window with lastrec on last row
  633.                     keystroke = 999
  634.                     GO BOTTOM
  635.                     SKIP -9
  636.                     cur_row = 22
  637.  
  638.                 ENDIF
  639.  
  640.             ELSE
  641.                 * fieldspec no good
  642.                 n = i
  643.  
  644.             ENDIF
  645.  
  646.         CASE keystroke = 6 .OR. keystroke = 23
  647.             * end or ^end
  648.             keystroke = 0
  649.             n = l_usr[AT(field_type, "CNDLM")]
  650.  
  651.         CASE keystroke = 1 .OR. keystroke = 29
  652.             * home or ^home
  653.             keystroke = 0
  654.             n = 1
  655.  
  656.         CASE keystroke = 22
  657.             * insert a new field before cursor
  658.  
  659.             IF stru_ck(.T.)
  660.                 n = 1                    && cursor on field name
  661.                 stru_ok = .F.            && fieldspec not valid
  662.                 is_append = .F.            && not append
  663.                 is_insert = .T.            && new field inserted
  664.                 rec1 = RECNO()            && remember which field
  665.  
  666.                 * insert blank not available..do it the hard way
  667.                 APPEND BLANK
  668.  
  669.                 DO WHILE rec1 < RECNO()
  670.                     * shift up for insert
  671.                     SKIP -1
  672.  
  673.                     * get previous fieldspec
  674.                     f_name = field_name
  675.                     f_type = field_type
  676.                     f_len = field_len
  677.                     f_dec = field_dec
  678.  
  679.                     * put into current fieldspec
  680.                     SKIP
  681.                     REPLACE field_name WITH f_name,field_type WITH f_type,;
  682.                             field_len WITH f_len,field_dec WITH f_dec
  683.  
  684.                     * next
  685.                     SKIP -1
  686.  
  687.                 ENDDO
  688.  
  689.                 * make current fieldspec look like new
  690.                 REPLACE field_name WITH SPACE(10),field_type WITH "C",;
  691.                         field_len WITH 10,field_dec WITH 0
  692.  
  693.                 IF cur_row < 22
  694.                     * scroll down for insert
  695.                     scroll((cur_row), 21, 22, 58, -1)
  696.  
  697.                 ENDIF
  698.  
  699.                 * newly added field looks like this
  700.                 @ cur_row,field_col[1] SAY not_empty
  701.  
  702.             ELSE
  703.                 * fieldspec no good
  704.                 n = i
  705.  
  706.             ENDIF
  707.  
  708.             keystroke = 0
  709.  
  710.         CASE keystroke = 7 .AND. LASTREC() > 1
  711.             * delete..only the current record can be invalid
  712.             rec1 = RECNO()
  713.             DELETE
  714.             PACK
  715.  
  716.             IF rec1 > LASTREC()
  717.                 * last record has been deleted
  718.                 GO BOTTOM
  719.  
  720.                 IF cur_row = 13
  721.                     * top of window
  722.                     stru_row(13)
  723.  
  724.                 ELSE
  725.                     @ cur_row,field_col[1] SAY empty_row
  726.                     cur_row = cur_row - 1
  727.  
  728.                 ENDIF
  729.  
  730.             ELSE
  731.  
  732.                 IF cur_row < 22
  733.                     * scroll bottom part of window up
  734.                     scroll((cur_row), 21, 22, 58, 1)
  735.  
  736.                 ENDIF
  737.  
  738.                 * go to last field on screen
  739.                 GOTO rec1
  740.                 SKIP 22 - cur_row
  741.  
  742.                 IF .NOT. EOF()
  743.                     * fill bottom row
  744.                     stru_row(22)
  745.  
  746.                 ELSE
  747.                     * put blank template on last row
  748.                     @ 22,field_col[1] SAY empty_row
  749.  
  750.                 ENDIF
  751.  
  752.                 * move pointer to current record
  753.                 GOTO rec1
  754.  
  755.                 * same recno, but not the same record
  756.                 prev_rec = 0
  757.  
  758.             ENDIF
  759.  
  760.             IF .NOT. is_append .AND. .NOT. is_insert
  761.                 * structure is altered..cannot change names
  762.                 altered = .T.
  763.                 chg_name = .F.
  764.  
  765.             ENDIF
  766.  
  767.             * re-set tracking variables
  768.             is_append = .F.                && append is off
  769.             is_insert = .F.                && insert is off
  770.             stru_ok = .T.                && only current record can be invalid
  771.             keystroke = 0
  772.  
  773.         CASE prev_rec <> RECNO()
  774.             * record pointer has been moved and all cascading
  775.             *     keystrokes have been processed
  776.             prev_rec = RECNO()
  777.  
  778.             * update field/record number on screen
  779.             @ 9,field_col[1] + 26 SAY "Field " + pad(LTRIM(STR(RECNO())), 5)
  780.  
  781.             IF n > l_usr[AT(field_type, "CNDLM")]
  782.                 * check for n out of range
  783.                 n = l_usr[AT(field_type, "CNDLM")]
  784.  
  785.             ENDIF
  786.  
  787.         CASE local_func = 4
  788.             * "save structure" selected from pull down menu..keystroke = 0
  789.             local_func = 0
  790.  
  791.             IF .NOT. stru_ck(.T.)
  792.                 * fieldspec no good
  793.                 n = i
  794.                 LOOP
  795.  
  796.             ENDIF
  797.  
  798.             is_append = .F.
  799.             is_insert = .F.
  800.             filename = stru_name
  801.  
  802.             IF filebox(".DBF", "dbf_list", "stru_title",;
  803.                        "do_modstru", .T., 13) <> 0
  804.                 * structure created or altered
  805.                 stru_name = filename
  806.  
  807.                 * re-write name at top of window
  808.                 @ 9,field_col[1] + 13;
  809.                 SAY pad(IF(EMPTY(stru_name), "<new file>",;
  810.                             SUBSTR(stru_name, RAT("\", stru_name) + 1)), 13)
  811.  
  812.                 IF aseek(dbf, filename) = 0
  813.                     * bring new file into view
  814.                     cur_dbf = filename
  815.  
  816.                     open_dbf(.F., .T.)
  817.  
  818.                     * select system reserved work area
  819.                     SELECT 10
  820.  
  821.                 ENDIF
  822.  
  823.                 * exit to main View screen
  824.                 keystroke = 27    && exit this routine
  825.                 cur_area = 0    && re-draw View screen
  826.  
  827.             ENDIF
  828.  
  829.             * clear message from screen
  830.             stat_msg("")
  831.  
  832.         CASE local_func = 1
  833.             * "help" selected from pull down menu..keystroke = 0
  834.             local_func = 0
  835.             DO syshelp
  836.  
  837.         OTHERWISE
  838.             * get new keystroke
  839.  
  840.             IF .NOT. key_ready()
  841.                 * hi-lite the current item as reverse
  842.                 SetColor(M->color2)
  843.                 stru_item()
  844.                 SetColor(M->color7)
  845.  
  846.                 * wait for keystroke
  847.                 read_key()
  848.  
  849.                 IF .NOT. (keystroke = 13 .OR. isdata(keystroke))
  850.                     * this is not a GET..re-write as normal
  851.                     stru_item()
  852.  
  853.                 ENDIF
  854.             ENDIF
  855.  
  856.             IF keystroke = 27 .AND. altered
  857.                 * warning
  858.  
  859.                 IF rsvp("Ok To Lose Changes? (Y/N)") <> "Y"
  860.                     keystroke = 0
  861.  
  862.                 ENDIF
  863.             ENDIF
  864.     ENDCASE
  865. ENDDO create/modify structure
  866.  
  867. * close and erase structure file..all done
  868. USE
  869. ERASE ddbbuuuu.ext
  870.  
  871. * clear status line
  872. stat_msg("")
  873.  
  874. * restore window
  875. RESTSCREEN(8, 20, 23, 59, M->wstru_buff)
  876.  
  877. SetColor(saveColor)
  878. RETURN
  879.  
  880.  
  881. *******************
  882. * local functions *
  883. *******************
  884.  
  885. ******
  886. *    stru_row()
  887. *
  888. *    fill one row in structure window
  889. ******
  890. FUNCTION stru_row
  891.  
  892. PARAMETERS fill_row
  893.  
  894. @ fill_row,field_col[1];
  895. SAY field_name + " │ " + data_type[AT(field_type, "CNDLM")] + " │ "
  896.  
  897. IF field_type = "C"
  898.     * display Clipper extended field length
  899.     @ fill_row,field_col[3] SAY STR(((256 * field_dec) + field_len), 4) +;
  900.                                 " │    "
  901.  
  902. ELSE
  903.     * normal field length
  904.     @ fill_row,field_col[3] SAY STR(field_len, 4) + " │    "
  905.  
  906.     IF field_type = "N"
  907.         * display decimals for numeric field
  908.         @ fill_row,field_col[4] SAY field_dec
  909.  
  910.     ENDIF
  911. ENDIF
  912.  
  913. RETURN 0
  914.  
  915.  
  916. ******
  917. *    stru_item()
  918. *
  919. *    display item in structure window
  920. ******
  921. FUNCTION stru_item
  922.  
  923. DO CASE
  924.  
  925.     CASE n = 1
  926.         * field_name
  927.         @ cur_row,field_col[1] SAY field_name
  928.  
  929.     CASE n = 2
  930.         * display field_type as character string
  931.         @ cur_row,field_col[2] SAY data_type[AT(field_type, "CNDLM")]
  932.  
  933.     CASE n = 3
  934.  
  935.         IF field_type = "C"
  936.             * display Clipper extended field length
  937.             @ cur_row,field_col[n] SAY STR(((256 * field_dec) +;
  938.                                            field_len),4)
  939.  
  940.         ELSE
  941.             * normal field_len
  942.             @ cur_row,field_col[n] SAY STR(field_len,4)
  943.  
  944.         ENDIF
  945.  
  946.     CASE n = 4
  947.         * field_dec
  948.         @ cur_row,field_col[4] SAY field_dec
  949.  
  950. ENDCASE
  951.  
  952. RETURN 0
  953.  
  954.  
  955. ******
  956. *    no_append()
  957. *
  958. *    eliminate newly appended field/record
  959. ******
  960. FUNCTION no_append
  961.  
  962. DELETE
  963. PACK
  964. GO BOTTOM
  965. SKIP
  966.  
  967. IF (RECNO() = cur_row - 12) .OR. keystroke = 5
  968.     * blank the current row
  969.     @ cur_row,field_col[1] SAY empty_row
  970.  
  971. ENDIF
  972.  
  973. stru_ok = .T.
  974.  
  975. RETURN 0
  976.  
  977.  
  978. ******
  979. *    stru_ck()
  980. *
  981. *    test fieldspec if needed
  982. ******
  983. FUNCTION stru_ck
  984.  
  985. PARAMETERS disp_err
  986.  
  987. IF .NOT. stru_ok
  988.     * fieldspec needs testing
  989.     i = field_check(disp_err)
  990.     stru_ok = (i = 0)
  991.  
  992. ENDIF
  993.  
  994. RETURN stru_ok
  995.  
  996.  
  997. ******
  998. *    field_check()
  999. *
  1000. *    return number of invalid field aspect (field_name = 1, etc.), 0 if ok
  1001. ******
  1002. FUNCTION field_check
  1003.  
  1004. PARAMETERS disp_err
  1005. PRIVATE pos,test_num,test_name,status,err_msg
  1006.  
  1007. * initialize local variables
  1008. status = 0
  1009. err_msg = ""
  1010.  
  1011. * test for valid field name
  1012. pos = LEN(TRIM(field_name))
  1013.  
  1014. IF pos = 0
  1015.     * blank
  1016.     status = 1
  1017.     err_msg = "Blank Field Name"
  1018.  
  1019. ENDIF
  1020.  
  1021. IF status = 0
  1022.  
  1023.     DO WHILE pos > 0 .AND. SUBSTR(field_name, pos, 1) $;
  1024.                            "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"
  1025.         * validate all characters except trailing spaces
  1026.         pos = pos - 1
  1027.  
  1028.     ENDDO
  1029.  
  1030.     * the first character must be a letter
  1031.     IF pos > 0 .OR. SUBSTR(field_name, 1, 1) $ "0123456789_"
  1032.         * invalid character
  1033.         status = 1
  1034.         err_msg = "Illegal Field Name"
  1035.  
  1036.         IF keystroke = 24
  1037.             * force error display for illegal down arrow
  1038.             disp_err = .T.
  1039.  
  1040.         ENDIF
  1041.     ENDIF
  1042. ENDIF
  1043.  
  1044. IF status = 0
  1045.     * look for duplicate field name
  1046.     test_num = RECNO()
  1047.     test_name = field_name
  1048.     LOCATE FOR field_name = test_name .AND. RECNO() <> test_num
  1049.  
  1050.     IF FOUND()
  1051.         * duplicate field name
  1052.         status = 1
  1053.         err_msg = "Duplicate Field Name"
  1054.  
  1055.         IF keystroke = 24
  1056.             * force error display for illegal down arrow
  1057.             disp_err = .T.
  1058.  
  1059.         ENDIF
  1060.     ENDIF
  1061.  
  1062.     * re-set pointer to current record
  1063.     GOTO test_num
  1064.  
  1065. ENDIF
  1066.  
  1067. IF status = 0
  1068.     * test for valid field_len
  1069.  
  1070.     IF field_type = "C"
  1071.         test_num = (256 * field_dec) + field_len
  1072.  
  1073.         IF test_num <= 0 .OR. test_num > 1024
  1074.             * invalid field width
  1075.             status = 3
  1076.             err_msg = "Invalid Field Width"
  1077.  
  1078.             IF keystroke = 24
  1079.                 * force error display for illegal down arrow
  1080.                 disp_err = .T.
  1081.  
  1082.             ENDIF
  1083.         ENDIF
  1084.  
  1085.     ELSE
  1086.  
  1087.         IF field_len <= 0 .OR. field_len > 19
  1088.             * invalid field width
  1089.             status = 3
  1090.             err_msg = "Invalid Field Width"
  1091.  
  1092.             IF keystroke = 24
  1093.                 * force error display for illegal down arrow
  1094.                 disp_err = .T.
  1095.  
  1096.             ENDIF
  1097.         ENDIF
  1098.     ENDIF
  1099. ENDIF
  1100.  
  1101. IF field_type = "N" .AND. status = 0
  1102.     * test for valid field_dec
  1103.  
  1104.     IF field_dec > IF(field_len < 3, 0, IF(field_len > 17, 15, field_len - 2))
  1105.         * invalid decimal width
  1106.         status = 4
  1107.         err_msg = "Invalid Decimal Width"
  1108.  
  1109.         IF keystroke = 24
  1110.             * force error display for illegal down arrow
  1111.             disp_err = .T.
  1112.  
  1113.         ENDIF
  1114.     ENDIF
  1115. ENDIF
  1116.  
  1117. IF status > 0 .AND. disp_err
  1118.     * something not right that ought to be shown
  1119.     error_msg(err_msg)
  1120.  
  1121. ENDIF
  1122.  
  1123. RETURN status
  1124.  
  1125.  
  1126. *********************************
  1127. * functions called from filebox *
  1128. *********************************
  1129.  
  1130. ******
  1131. *    stru_title()
  1132. *
  1133. *    display title for save structure filebox
  1134. ******
  1135. FUNCTION stru_title
  1136.  
  1137. PARAMETERS sysparam
  1138.  
  1139. RETURN box_title(M->sysparam, "Save structure as...")
  1140.  
  1141.  
  1142. ******
  1143. *    do_modstru()
  1144. *
  1145. *    create/modify structure
  1146. ******
  1147. FUNCTION do_modstru
  1148.  
  1149. PRIVATE stru_done, i, is_open, new_name, name_temp, add_name,;
  1150.         dbt_spec, dbt_temp, rec1
  1151.  
  1152. DO CASE
  1153.  
  1154.     CASE EMPTY(filename)
  1155.         error_msg("File name not entered")
  1156.         stru_done = .F.
  1157.  
  1158.     OTHERWISE
  1159.         * determine if structure to be created is currently open
  1160.         i = aseek(dbf, filename)
  1161.         is_open = (i > 0)
  1162.  
  1163.         IF FILE(filename) .AND. .NOT. (filename == cur_dbf)
  1164.             * file exists and is not the current data file being modified
  1165.  
  1166.             IF rsvp(filename + IF(is_open, " Is Currently Open",;
  1167.                                            " Already Exists") +;
  1168.                     "...Overwrite? (Y/N)") <> "Y"
  1169.                 * oops
  1170.                 RETURN .F.
  1171.  
  1172.             ENDIF
  1173.         ENDIF
  1174.  
  1175.         IF is_open
  1176.             * can't really modify an open file, but we make it look that way
  1177.             name_temp = "ntx" + SUBSTR("123456", i, 1)
  1178.             need_ntx = need_ntx .OR. .NOT. EMPTY(&name_temp[1])
  1179.  
  1180.             * temporarily disable any relations targeted at the open file
  1181.             not_target(i, .F.)
  1182.  
  1183.             * close the file
  1184.             SELECT (M->i)
  1185.             USE
  1186.  
  1187.             name_temp = "kf" + SUBSTR("123456", i, 1)
  1188.  
  1189.             IF .NOT. EMPTY(&name_temp)
  1190.                 * will need to re-set the filter for the open file
  1191.                 need_filtr = .T.
  1192.  
  1193.             ENDIF
  1194.  
  1195.             * select system reserved work area
  1196.             SELECT 10
  1197.  
  1198.         ENDIF
  1199.  
  1200.         * remember the current field number and close structure file
  1201.         rec1 = RECNO()
  1202.         USE
  1203.  
  1204.         * remember if file existed in current directory before
  1205.         add_name = .NOT. FILE(name(filename) + ".DBF")
  1206.  
  1207.         IF FILE(filename)
  1208.             * file exists..modify structure and save old data
  1209.             new_name = " "
  1210.  
  1211.             IF chg_name .AND. altered
  1212.                 * rsvp change of field names
  1213.                 new_name = rsvp("Change Field Name(s)? (Y/N)")
  1214.  
  1215.                 IF .NOT. new_name $ "YN"
  1216.                     * Escape key will cancel the operation
  1217.                     USE ddbbuuuu.ext
  1218.                     GOTO rec1
  1219.                     RETURN .F.
  1220.  
  1221.                 ENDIF
  1222.             ENDIF
  1223.  
  1224.             * establish temp filespec and dbt specs in same directory
  1225.             name_temp = SUBSTR(filename, 1, RAT("\", filename)) +;
  1226.                         "DDBBUUUU.TMP"
  1227.             dbt_spec = SUBSTR(filename, 1, RAT(".", filename)) +;
  1228.                        "DBT"
  1229.             dbt_temp = SUBSTR(name_temp, 1, RAT(".", name_temp)) +;
  1230.                        "DBT"
  1231.  
  1232.             IF FILE(dbt_spec)
  1233.                 * data file contains memo fields
  1234.  
  1235.                 IF new_name = "Y"
  1236.                     * field_name change will lose memos during SDF copy
  1237.                     new_name = rsvp("Warning: Memos Will Be Lost" +;
  1238.                                     "...Proceed? (Y/N)")
  1239.  
  1240.                     IF new_name <> "Y"
  1241.                         * abort operation
  1242.                         USE ddbbuuuu.ext
  1243.                         GOTO rec1
  1244.                         RETURN .F.
  1245.  
  1246.                     ENDIF
  1247.                 ENDIF
  1248.  
  1249.                 * every dbt has its dbf
  1250.                 RENAME &dbt_spec TO &dbt_temp
  1251.  
  1252.             ENDIF
  1253.  
  1254.             stat_msg(IF(new_name <> "Y", "Altering file structure",;
  1255.                         "Changing field name(s)"))
  1256.  
  1257.             * save the old and create the new
  1258.             RENAME &filename TO &name_temp
  1259.             CREATE &filename FROM ddbbuuuu.ext
  1260.  
  1261.             IF new_name = "Y"
  1262.                 * change field names by copying SDF
  1263.                 USE &name_temp
  1264.                 COPY TO ddbbuuuu.txt SDF
  1265.                 USE &filename
  1266.                 APPEND FROM ddbbuuuu.txt SDF
  1267.                 ERASE ddbbuuuu.txt
  1268.  
  1269.             ELSE
  1270.                 * normal modify structure
  1271.                 APPEND FROM &name_temp
  1272.  
  1273.             ENDIF
  1274.  
  1275.             IF FILE(name_temp)
  1276.                 * delete temp file
  1277.                 ERASE &name_temp
  1278.  
  1279.             ENDIF
  1280.  
  1281.             IF FILE(dbt_temp)
  1282.                 * delete temp dbt file
  1283.                 ERASE &dbt_temp
  1284.  
  1285.             ENDIF
  1286.  
  1287.             IF is_open
  1288.                 * re-establish file in its original select area
  1289.                 USE                    && close in system reserved area
  1290.                 SELECT (M->i)        && select the correct area
  1291.                 USE &filename        && re-open the file
  1292.  
  1293.                 * establish new field list for new structure
  1294.                 name_temp = "field_n" + SUBSTR("123456", M->i, 1)
  1295.                 all_fields(M->i, &name_temp)
  1296.  
  1297.                 * re-select system reserved area
  1298.                 SELECT 10
  1299.  
  1300.             ENDIF
  1301.  
  1302.         ELSE
  1303.             * create new file
  1304.             stat_msg("Creating new data file")
  1305.             CREATE &filename FROM ddbbuuuu.ext
  1306.             USE
  1307.  
  1308.             IF AT(".DBF", filename) = LEN(filename) - 3 .AND.;
  1309.                FILE(name(filename) + ".DBF") .AND. add_name
  1310.                 * add only .dbf files in the current directory
  1311.                 i = afull(dbf_list) + 1
  1312.  
  1313.                 IF i <= LEN(dbf_list)
  1314.                     * add new file name to list
  1315.                     dbf_list[i] = filename
  1316.                     array_sort(dbf_list)
  1317.  
  1318.                 ENDIF
  1319.             ENDIF
  1320.         ENDIF
  1321.  
  1322.         * close newly created or modified file
  1323.         USE
  1324.         stru_done = .T.
  1325.  
  1326. ENDCASE
  1327.  
  1328. RETURN stru_done
  1329.  
  1330.  
  1331. * EOF DBUSTRU.PRG
  1332.